Skip to content

fix(rivetkit): run db migrations before lifecycle hooks#4780

Draft
NathanFlurry wants to merge 1 commit intodriver-fixes/sqlite-startup-takeover-racesfrom
driver-fixes/db-migrate-before-lifecycle
Draft

fix(rivetkit): run db migrations before lifecycle hooks#4780
NathanFlurry wants to merge 1 commit intodriver-fixes/sqlite-startup-takeover-racesfrom
driver-fixes/db-migrate-before-lifecycle

Conversation

@NathanFlurry
Copy link
Copy Markdown
Member

Description

Please include a summary of the changes and the related issue. Please also include relevant motivation and context.

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

Please describe the tests that you ran to verify your changes.

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

Copy link
Copy Markdown
Member Author

NathanFlurry commented Apr 26, 2026

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@claude
Copy link
Copy Markdown

claude Bot commented Apr 26, 2026

Code Review: fix(rivetkit): run db migrations before lifecycle hooks

Summary

This PR fixes a bug in the NAPI receive-loop preamble where onMigrate was running after createState, onCreate, and createVars, making c.db unavailable to those lifecycle hooks. The fix moves the onMigrate call to the top of run_preamble, before any user lifecycle hook. Three driver integration tests are added to verify the new ordering.


Correctness of the Core Fix

The reordering in run_preamble is correct. The new NAPI preamble sequence is:

  1. onMigrate (moved to first)
  2. If new: createStateonCreatemark_has_initialized
  3. If wake: load snapshot → restore hibernatable connections
  4. createVars (runs for both new and wake)
  5. init_alarmsmark_readyonWakeonBeforeActorStartmark_started

This matches the TypeScript driver (actor/instance/mod.ts: await this.#setupDatabase(preload) is called unconditionally before all lifecycle hooks). The fix correctly achieves parity between the NAPI and TypeScript execution paths.


Issues Found

1. Weak assertion in the createState test (minor)

In actor-db-init-order.test.ts, the second assertion only checks typeof (await nextActor.getInitialCount()) === "number" rather than asserting an exact value. Since createState captures the DB row count once at actor creation time (which is 0), the assertion should be toBe(0) to be meaningful. As written, even a broken implementation returning NaN would pass this check (since typeof NaN === "number" is true), so this assertion does not catch the -1 fallback sentinel case either.

Suggested fix:

expect(await nextActor.getInitialCount()).toBe(0);

2. No test coverage for onWake accessing c.db

The PR comment in napi_actor_events.rs says migrations run before createState, onCreate, and createVars — but onWake is also a lifecycle hook that now has c.db available. Consider adding a fixture actor with an onWake handler that queries c.db and a sleep/wake test case to close the coverage gap. This can be a follow-up if preferred.

3. No test for createVars on the wake path

createVars runs on both first-creation and wake. The new tests only cover the first-creation case. A test that triggers sleep, wakes the actor, and verifies createVars can access the migrated schema would complete the coverage matrix.

4. PR description not filled in

The PR body uses the unfilled template text. Please add at minimum: the bug description, root cause, and what was manually tested.


Convention Checks

  • Rust comment is a well-formed complete sentence ending with a period. ✓
  • No eprintln!/println! logging introduced. ✓
  • No new Mutex<HashMap> or async lock anti-patterns. ✓
  • No _ => fall-through arms on enums. ✓
  • No vi.mock/jest.mock in the new test file. ✓
  • No vi.waitFor calls without justification comments (none used, appropriate). ✓
  • Conventional commit title format (fix(rivetkit): ...) is correct. ✓

Verdict

The core fix is correct and well-targeted. Main actionable items:

  1. Strengthen the weak typeof === "number" assertion to toBe(0) in the createState test — the current assertion does not catch -1 or NaN.
  2. Fill in the PR description with the bug description, root cause, and test notes.
  3. Consider adding a sleep/wake + onWake-with-db test case as a follow-up to complete coverage.

@github-actions
Copy link
Copy Markdown
Contributor

Preview packages published to npm

Install with:

npm install rivetkit@pr-4780

All packages published as 0.0.0-pr.4780.9ec431f with tag pr-4780.

Engine binary is shipped via @rivetkit/engine-cli on linux-x64-musl, linux-arm64-musl, darwin-x64, and darwin-arm64. Windows users should use the release installer or set RIVET_ENGINE_BINARY.

Docker images:

docker pull rivetdev/engine:slim-9ec431f
docker pull rivetdev/engine:full-9ec431f
Individual packages
npm install rivetkit@pr-4780
npm install @rivetkit/react@pr-4780
npm install @rivetkit/rivetkit-napi@pr-4780
npm install @rivetkit/workflow-engine@pr-4780

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