Skip to content

perf: shut down container services concurrently (#1322) - #1326

Closed
groupthinking wants to merge 1 commit into
mainfrom
claude/determined-maxwell-dbco8k
Closed

perf: shut down container services concurrently (#1322)#1326
groupthinking wants to merge 1 commit into
mainfrom
claude/determined-maxwell-dbco8k

Conversation

@groupthinking

Copy link
Copy Markdown
Owner

Canonical issue

Closes #1322

Outcome

ServiceContainer.shutdown is the FastAPI shutdown handler, so it runs inside the SIGTERM grace window on every deploy and restart. This PR removes two defects in that path:

  • Serial teardown → concurrent. The old for loop awaited each service's close()/cleanup() in turn, so total cost was the sum of every teardown round-trip. Services are independent with no declared teardown ordering, so they now tear down under a single asyncio.gather(..., return_exceptions=True); cost becomes the slowest single teardown, and the previous "log and continue" behaviour is preserved per-service.
  • Double-close of aliased singletons. _register_skill_dependency_aliases registers four aliases whose factories delegate to get_service, which caches into _singletons, so one instance can be stored under several names. The old loop called cleanup() once per name, double-closing sessions/pools. Targets are now deduplicated by object identity (id()).
  • Sync-hook safety. Teardown hooks may be synchronous; the result is now awaited only when inspect.isawaitable(result), matching the api_cost_worker idiom and removing a spurious "await NoneType" error previously logged for sync cleanup().

Scope

  • Included: src/youtube_extension/backend/containers/service_container.py (extract _shutdown_service, concurrent shutdown), tests/unit/test_service_container.py (new TestShutdownConcurrency).
  • Explicitly excluded: no changes to service registration, resolution, or health-check logic; no teardown-ordering guarantees introduced.

Risk

  • Risk level: low
  • Failure mode: if two services shared an undeclared teardown ordering dependency, concurrent teardown could surface it — none is declared or currently relied upon.
  • Rollback: revert this commit; the previous serial teardown is a clean revert.

Verification

  • Focused tests — PYTHONPATH=src pytest tests/unit/test_service_container.py63 passed at head 482d7fd. New cases cover concurrent in-flight teardown, alias dedup (torn down once), distinct-service teardown, synchronous cleanup() support, and one-failure-does-not-block-others.
  • Required CI — pending on this head.
  • Review threads resolved — none yet.

Production evidence

Not applicable — this is a backend process-shutdown path (SIGTERM grace window). No UI/preview surface; effect is observable only in deploy/restart teardown timing and logs.

Agent handoff

Agent provenance

This PR publishes a previously-committed, human-authored fix (commit 482d7fd, author Hayden, co-authored by Copilot App) that closes #1322 but had not been pushed or opened as a PR. No separate agent run produced the diff, so no agent-lock-manifest evidence is asserted here.


Generated by Claude Code

ServiceContainer.shutdown is the FastAPI shutdown handler, so it runs
inside the SIGTERM grace window on every deploy and restart. It had two
defects.

Teardown was serial: a for loop awaited each service in turn, making
total cost the sum of every close() round-trip rather than the slowest
one. The services are independent and no teardown ordering was declared
or guaranteed, so they now tear down under a single asyncio.gather.
Exceptions are collected via return_exceptions and reported per service,
preserving the previous "log and continue" behaviour.

Aliased singletons were cleaned up twice. _register_skill_dependency_
aliases registers four aliases whose factories delegate to get_service,
which caches into _singletons, so one instance ends up stored under two
names. The loop then called cleanup() on it once per name, double
closing sessions and pools. Targets are now deduplicated by identity.

Teardown hooks may also be synchronous, so the result is awaited only
when inspect.isawaitable, matching the idiom in api_cost_worker. This
removes a spurious "await NoneType" error previously logged for sync
cleanup().

Closes #1322

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@vercel

vercel Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
v0-uvai Ready Ready Preview, v0 Aug 4, 2026 2:45am

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are limited based on label configuration.

🏷️ Required labels (at least one) (1)
  • [‘architecture-gap’, ‘bug’, ‘ci-cd’, ‘ci/cd’, ‘copilot-rabbit’, ‘documentation’, ‘duplicate’, ‘enhancement’, ‘frontend’, ‘github_actions’, ‘good first issue’, ‘help wanted’, ‘high-priority’, ‘invalid’, ‘javascript’, ‘ml-model’, ‘needs-triage’, ‘pipeline-critical’, ‘placeholder-code’, ‘priority:high’, ‘python’, ‘python:uv’, ‘question’, ‘styling’, ‘tests’, ‘v0’]

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8f2fc96d-299c-4a82-8f9d-9d9e976d4be5

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Snapshot Warnings

⚠️: No snapshots were found for the head SHA 482d7fd.
Ensure that dependencies are being submitted on PR branches and consider enabling retry-on-snapshot-warnings. See the documentation for more information and troubleshooting advice.

Scanned Files

None

@github-actions github-actions Bot added the python label Aug 4, 2026
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown

Agent Completion Truth Gate: BLOCKED

Reasons: invalid_payload

Machine-readable verdict
{
  "details": {
    "invalid_fields": [
      "policy.agent_login",
      "policy.run_id"
    ]
  },
  "reasons": [
    "invalid_payload"
  ],
  "verdict": "blocked"
}

Workflow evidence

Copy link
Copy Markdown
Owner Author

Status — functional checks green; blocked only on the advisory gate + human merge approval

Functional verification (head 482d7fd):

  • ✅ Focused tests — PYTHONPATH=src pytest tests/unit/test_service_container.py63 passed locally (concurrent-teardown in-flight, alias dedup, distinct-service teardown, sync cleanup() support, one-failure-isolation).
  • ✅ Vercel — preview Ready / Deployed.
  • ✅ Dependency Review — no vulnerabilities/license issues (snapshot warning is benign; this PR changes no dependencies).
  • ➖ CodeRabbit — review skipped (label configuration), no findings.

The one red check — agent-completion/truth-gate/pr-1326invalid_payload:

{ "reasons": ["invalid_payload"], "details": { "invalid_fields": ["policy.agent_login", "policy.run_id"] } }

The gate treats this as agent work because the branch is prefixed claude/, then blocks because it finds no agent provenance to bind. That is correct: this PR republishes an already-committed, human-authored fix (commit 482d7fd, author Hayden, co-authored by Copilot App) that closed #1322 but had never been pushed or opened as a PR. There is no agent task/run behind the diff, so policy.agent_login/policy.run_id are legitimately absent — and they must not be manufactured (that is precisely the provenance forgery this gate is designed to reject).

Per the repo's own docs/agent-completion-truth-gate.md, this status is advisory and must not be a required check (until #874). It does not block merge. The actual merge gate here is human: mark ready + approve + merge to protected main.

No code change is warranted on this PR. The diff is verified and functionally green. Not pushing a new commit, because that would only re-trigger the same advisory gate and reset the head with no benefit.

Note for maintainers: the truth-gate workflow is faulting with invalid_payload (rather than evaluating to a clean blocked verdict) across multiple draft/agent-branch PRs — the same infrastructure issue flagged in the 2026-07-31 remediation run. Worth a look independently of any single PR.


Generated by Claude Code

Copy link
Copy Markdown
Owner Author

Closing as a duplicate — this work is already merged into main.

The identical container-shutdown fix for #1322 landed via #1323 (branch perf/container-shutdown, merged by @groupthinking at 2026-08-04 02:39:50 UTC). This PR was opened at 02:44 on the working branch claude/determined-maxwell-dbco8k, which happened to still carry the same commit (482d7fd) — so it re-proposes changes that are now in main (_shutdown_service is present on origin/main). Confirmed: no unique diff remains.

The red checks here are moot and not worth chasing on a duplicate:

No action needed — #1322 is resolved by #1323. Closing.


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

perf: ServiceContainer.shutdown tears services down serially and cleans aliases twice

1 participant