2.5 KiB

name description version category
standalone-sage-deployment Sage-lib standalone deploy. DictObject/DBPools fixes. 1.0.0 devops

Standalone Sage-Based App Deployment

When deploying standalone apps using Sage shared libs without the Sage framework.

Required Monkey-Patches

DictObject.getattr returns None not AttributeError

Blocks class-level method resolution. Must monkey-patch.

ServerEnv NOT a singleton

set_serverenv() needed for cross-instance values.

DBPools() defaults to empty

4 patches needed: sqlor.dbpools.get_sor_context, GlobalEnv cache, userperm, set_serverenv.

Ahserver dspy filename reservation

ANY dspy filename containing login, auth, signin, or identify returns 404 silently. Use single dictionary words or random strings. Full list + debugging: see references/dspy-pitfalls.md.

dspy failure cache — PERMANENT

Once a dspy file fails, that filename is cached forever. Content change + restart does NOT clear it. Only fix: use a NEW filename. Copy from a working dspy first, then overwrite. See references/dspy-pitfalls.md.

aiohttp 3.10 route matching: prefix must be "" NOT "/"

ProcessorResource(prefix="/", dir="/d/xxx/wwwroot") — the "/" prefix causes ProcessorResource._handle to NEVER be called; aiohttp falls through to SystemRoute._handle → 404.

Fix: use empty string prefix in config.json:

"paths": [["/d/pccs/wwwroot", ""]]

Single catch-all entry works — NO per-module paths needed. Empty prefix "" avoids aiohttp 3.10's StaticResource.resolve() bug with "/" prefix + session middleware interaction.

module_cache.rbac interaction

When enabled (default): share_cache calls Redis. Redis OFF → 500 for ALL requests. Disable with "module_cache": {"rbac": false} in config.json if Redis not available.

Shared libs (ahserver, apppublic, sqlor, appbase, rbac) must be pip installed. Sage modules (pcpool, pcc, etc.) have only setup.json — use ln -sfn for wwwroot symlinks.

DSPY login: must use password_encode() NOT SHA256

The Sage framework stores passwords via password_encode() which uses AES encryption. In custom login dspy files, use the injected password_encode(password) function:

pw_encoded = password_encode(password)
# Compare with user.password from DB
if pw_encoded != (user.password or ''):
    return {'status': 'error', 'message': '密码错误'}

SHA256 will never match the AES-encrypted stored value.