fix: make orchestrator teardown timeout configurable #436
Reference in New Issue
Block a user
Delete Branch "fix/orchestrator-teardown-timeout"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #435.
Summary
OrchestratorConfigStore— a key/value table (orchestrator_config) co-tenanted in the sharedbot-bottle.dbusing the existingDbStore/TableMigrationspattern.resolve_teardown_timeout()implementing the priority chain:BOT_BOTTLE_ORCHESTRATOR_TEARDOWN_TIMEOUT_SECONDSenv var →teardown_timeout_secondsDB key → default of 30 s (up from 5 s).teardown_consolidated()in all three backends (macos_container, docker, firecracker) gains an optionaltimeoutkeyword arg; it defaults toDEFAULT_TEARDOWN_TIMEOUT_SECONDSwhen not supplied so the rollback path inregister_agentis unaffected.launch.pyresolves the timeout at callback-registration time and passes it tostack.callback.660951baf5to3674d7780bFound one blocking lifecycle issue:
P2 — Resolve the timeout before registering the bottle. In each backend launch path,
resolve_teardown_timeout()is evaluated only afterlaunch_consolidated()/register_agent()has registered the bottle and provisioned git-gate state. The resolver can raise during database creation or migration—for example, when SQLite remains locked beyond its five-second busy timeout. Becausestack.callback()has not completed in that case, no teardown callback exists, leaving an orphaned registration and provisioned state. Resolve the timeout before registration, or ensure resolution cannot raise.The unit suite passes. The new configuration and teardown paths have no dedicated tests, including this failure ordering.
Fixed both issues in
31000dc.P2 — Resolve the timeout before registering the bottle. In each of the three launch paths (docker, firecracker, macos_container),
resolve_teardown_timeout()is now evaluated into ateardown_timeoutlocal variable before thelaunch_consolidated()/register_agent()call. If the resolver raises, the bottle has not been registered yet, so no orphaned state is left behind.Coverage. Added
tests/unit/test_orchestrator_config_store.py(18 tests):OrchestratorConfigStoreCRUD andis_migrated()behaviourresolve_teardown_timeoutpriority ordering (env var → DB → default), invalid/non-positive env var and DB values, and auto-migration on first callTestTeardownTimeoutResolvedBeforeRegistration): one test per backend asserting that theteardown_timeout = resolve_teardown_timeout()assignment appears before the registration call in the source, so a future refactor that regresses the ordering will fail immediatelyRereviewed at
3057043. The prior lifecycle blocker is resolved: all three backends now resolve the timeout before registration, so resolver failures cannot orphan registered state. I also fixed the lint failure in3057043(removed the unused import and typed the source-inspection helper). Verified: pyright (0 errors), targeted config-store tests (18 passed), full unit suite (1,901 passed), pylint on the changed test (9.80/10), and git diff --check. No remaining blocking findings.Rereview complete: prior blocker resolved; lint fixed; all verification passed.
@@ -0,0 +25,4 @@"""CREATE TABLE IF NOT EXISTS orchestrator_config (key TEXT PRIMARY KEY,value TEXT NOT NULLShouldn't be a generic key value store, should have an explicit schema (want a
teardown_timeout_secondscolumn)@@ -0,0 +23,4 @@["""CREATE TABLE IF NOT EXISTS orchestrator_config (id INTEGER PRIMARY KEY CHECK (id = 1),Done in
256a4b2. The generickey/valuetable is replaced with an explicit single-row schema:OrchestratorConfigStorenow exposesget/set/delete_teardown_timeout_seconds()instead of the genericget/set/delete(key).TEARDOWN_TIMEOUT_KEYis removed. The REAL column meansresolve_teardown_timeout()no longer needs afloat()conversion.