Skip to content

fix(server): prevent live session resource leaks on shutdown - #1276

Open
morluto wants to merge 2 commits into
MoonshotAI:mainfrom
morluto:fix/close-live-sessions-on-shutdown
Open

fix(server): prevent live session resource leaks on shutdown#1276
morluto wants to merge 2 commits into
MoonshotAI:mainfrom
morluto:fix/close-live-sessions-on-shutdown

Conversation

@morluto

@morluto morluto commented Jul 1, 2026

Copy link
Copy Markdown

Related Issue

Fixes #1273

Problem

Server shutdown currently disposes the DI graph without first closing live KimiCore sessions.

Formal proof of the bug:

  1. KimiCore owns live sessions in this.sessions.
  2. KimiCore.closeSession() closes exactly one session by calling session.close(), then removes that session from the map.
  3. Before this change, server shutdown closed WebSocket connections and Fastify, then called ix.dispose().
  4. Before this change, CoreProcessService.dispose() only marked the core process service as disposed so future RPC calls reject. It did not call Session.close() for live sessions.
  5. Session.close() is the path that cancels active turns, stops background tasks, flushes metadata, emits session-end behavior, shuts down MCP, and closes the session log handle.
  6. Therefore, if the server shuts down while sessions are still live and no client explicitly closed them first, those sessions skip normal Session.close() cleanup.

Impact:

Live sessions can leave session-owned work and resources running past server shutdown, including active turns, background tasks, MCP transports, unflushed metadata, and log handles.

What changed

Added a core lifecycle method that closes all live sessions before disposal.

The implementation snapshots the live session map, attempts to close every session, deletes each entry after its close attempt, and reports any close failures with an AggregateError after all sessions have been attempted.

Server shutdown now awaits this lifecycle method before disposing the DI graph. If one or more session closes fail, shutdown logs a warning and continues with the existing best-effort cleanup path.

A focused regression test covers both important behaviors:

  • every live session is closed and removed;
  • later sessions are still closed even when one session close fails.

Validation

  • pnpm --filter @moonshot-ai/agent-core exec vitest run test/rpc/core-close-all.test.ts passes: 1 file, 2 tests.

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked a related issue, or explained the problem above.
  • I have added tests that prove my feature works.
  • Ran gen-changesets skill, or this PR needs no changeset.
  • Ran gen-docs skill, or this PR needs no doc update.

@changeset-bot

changeset-bot Bot commented Jul 1, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 9339a2f

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@moonshot-ai/kimi-code Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

xsyetopz added a commit to xsyetopz/kimi-code that referenced this pull request Jul 31, 2026
Phase 1 — Non-PR issues (5):

- MoonshotAI#94: Read tool status now reports both MAX_LINES and MAX_BYTES when both
  limits are hit (was: else-if chain only reported the first). Fixed in v1
  (agent-core) and v2 (agent-core-v2). Added test for dual-limit case.

- MoonshotAI#250: KIMI_MODEL_* env config no longer gives OpenAI/Anthropic models the
  Kimi default capabilities (image_in, thinking). DEFAULT_CAPABILITIES is now
  a per-provider-type map: kimi gets ['image_in','thinking'], openai/anthropic
  get []. Fixed in v1 (env-model.ts) and v2 (envOverlay.ts). Added 2 tests.

- MoonshotAI#1972: Skill descriptions exceeding the 250-char model listing limit now
  emit a warning via onWarning during loadRoots, so the user knows the model
  sees a truncated version. Added 2 tests (warns / does not warn).

- MoonshotAI#1982: Added disabled_skills config denylist. config.toml now accepts
  disabled_skills = ['skill-name']. Matching skills (case-insensitive) are
  hidden from getSkill, getPluginSkill, listSkills, listInvocableSkills,
  register, loadRoots, and the TUI slash menu. Wired through SessionSkillConfig,
  resolveSessionSkillConfig, and TOML serialization. Added 3 tests.

- MoonshotAI#2224: Plugin-qualified skill names (e.g. 'superpowers:systematic-debugging')
  are now resolved by the native Skill tool. Falls back to getPluginSkill when
  bare-name getSkill misses and the name contains ':'. Fixed in v1 (skill-tool.ts)
  and v2 (skillTool.ts). Added 2 tests.

Phase 2 — PR-matching issues (5):

- MoonshotAI#1008 (PR MoonshotAI#1096): Web UI session archive relabeled from 'Archive' to 'Delete'.
  Confirm message now states the action is irreversible (en + zh).

- MoonshotAI#1106 (PR MoonshotAI#1108): WebSearch and FetchURL tools now forward the abort signal
  from ExecutableToolContext through to fetch() calls. Updated provider
  interfaces (WebSearchProvider, UrlFetcher) and all 3 provider implementations
  (MoonshotWebSearch, MoonshotFetchURL, LocalFetchURL). Updated 2 tests.

- MoonshotAI#1050 (PR MoonshotAI#1052): kosong streaming response loop now has an idle timeout
  (default 60s, configurable via idleTimeoutMs). Replaced bare for-await with
  manual iterator + Promise.race against timeout. Throws APITimeoutError on
  idle. Fixed in v1 (kosong/generate.ts) and v2 (agent-core-v2/generate.ts).
  Added 9 tests.

- MoonshotAI#1148 (PR MoonshotAI#1208): max_tokens/max_output_tokens now clamped to 128k ceiling
  in openai-legacy generate() and openai-responses withMaxCompletionTokens() +
  generate(). Kimi provider left unchanged (upstream clamping is intentional).
  Added 4 tests.

- MoonshotAI#1273 (PR MoonshotAI#1276): Added KimiCore.dispose() which iterates all live sessions
  and calls session.close() via Promise.allSettled. Wired into
  CoreProcessService.dispose(). Idempotent. Added 5 tests.

Skipped (already fixed in fork): MoonshotAI#1539, MoonshotAI#244, MoonshotAI#1218.
Checklist: .tmp/upstream-tracking/ISSUE-RESOLUTION-CHECKLIST.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Server shutdown can leak live session resources

1 participant