Skip to content

feat(server): drain resident WAL writers on graceful shutdown - #167

Merged
beinan merged 1 commit into
mainfrom
graceful-shutdown-drain
Jul 22, 2026
Merged

feat(server): drain resident WAL writers on graceful shutdown#167
beinan merged 1 commit into
mainfrom
graceful-shutdown-drain

Conversation

@beinan

@beinan beinan commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • ShardWriter has no Drop, so its background tasks are only reclaimed by an explicit close().await. At process shutdown the runtime is about to stop, so the detached best-effort close in RolloutStore::Drop may never run — leaking those tasks / skipping a clean drain.
  • Adds AppState::shutdown(), which snapshots the resident LRU and awaits RolloutStore::close() on each handle. Wired into main right after axum::serve(...).with_graceful_shutdown(...) returns (connections already drained). Idempotent and a no-op on an empty cache.

Test plan

  • cargo test -p lance-context-server state:: (incl. new shutdown_closes_resident_writers)
  • cargo clippy -p lance-context-server clean
  • cargo fmt --all

Note: this branch is independent of #166; it does not touch the cleanup_interval_secs removal.

🤖 Generated with Claude Code

`ShardWriter` has no `Drop`, so its background tasks are only reclaimed
by an explicit `close().await`. At process shutdown the runtime is about
to stop, so the detached best-effort close in `RolloutStore::Drop` may
never run. Add `AppState::shutdown()` to await `close()` on every
resident rollout writer, and call it in `main` after `axum::serve`
returns (connections drained). Idempotent and a no-op on an empty cache.

Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
beinan added a commit that referenced this pull request Jul 22, 2026
…#168)

## Summary
- `AppError::from_lance` took `impl Display` and string-matched the
rendered message (`"not found"`, `"Invalid"`, `"DatasetNotFound"`). That
is brittle (breaks on any Display wording change) and over-broad (any
message containing `"Invalid"` — e.g. `InvalidTableLocation`,
`InvalidRef` — became a 400).
- Now takes `lance::Error` by value (re-exported as `LanceError` from
`lance-context-core`) and matches **typed variants**:
`DatasetNotFound`/`NotFound` → 404, `DatasetAlreadyExists` → 409,
`InvalidInput`/`SchemaMismatch` → 400, else 500.
- The one signal Lance exposes no dedicated variant for — "compaction
already in progress", raised as an `ArrowError::InvalidArgumentError`
folded into Lance's generic `Arrow` variant — is still matched by text,
but checked **up front** so it keeps mapping to 409
`COMPACTION_IN_PROGRESS`.
- All call sites already passed `lance::Error`, so no caller changes
were needed.

## Test plan
- [x] `cargo test -p lance-context-server error::` (typed-variant
mapping + Arrow-wrapped compaction case)
- [x] `cargo clippy -p lance-context-server -p lance-context-core` clean
- [x] `cargo fmt --all`

Independent of #166 and #167.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4 <noreply@anthropic.com>
@beinan
beinan merged commit c3941b9 into main Jul 22, 2026
9 checks passed
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.

1 participant