Skip to content

feat(rivetkit): expose c.keepAwake(promise) through native path#4748

Draft
NathanFlurry wants to merge 1 commit intosleep-cleanup/06-ts-deprecate-prevent-sleepfrom
sleep-cleanup/07-keep-awake-native-api
Draft

feat(rivetkit): expose c.keepAwake(promise) through native path#4748
NathanFlurry wants to merge 1 commit intosleep-cleanup/06-ts-deprecate-prevent-sleepfrom
sleep-cleanup/07-keep-awake-native-api

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 24, 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 24, 2026

PR Review: feat(rivetkit): expose c.keepAwake(promise) through native path

Overview

This PR routes the native-path keepAwake through a new keep_awake NAPI method that directly uses rivetkit-core's keep-awake counter (via a KeepAwakeGuard), replacing the previous registerTask approach. The core semantics are the same - prevent idle sleep while the promise is in flight - but the mechanism is now more direct and properly maps to the SleepController keep-awake counter.


Issues

1. Silent error swallowing (significant)

The old code explicitly caught and only swallowed isClosedTaskRegistrationErrors, rethrowing everything else. The new code uses void on the returned Promise, which silently drops all errors, including genuine unexpected failures from callNative. This violates the project's fail-by-default rule.

If the wrapped JS promise rejects, the NAPI keep_awake method propagates that rejection back through the bridge, callNative normalizes it into a RivetError, and then void silently discards it with no log or warning. Compare to wait_until in Rust, which explicitly logs a warning on rejection.

Suggested fix - add a .catch to at least warn on unexpected bridge errors:

void callNative(() =>
    this.#ctx.keepAwake(promise.then(() => null)),
).catch((error) => {
    if (!isClosedTaskRegistrationError(error)) {
        logger().warn('keep_awake bridge error', { error });
    }
});

Alternatively, restructure the NAPI method to match the wait_until pattern: handle the rejection inside Rust with a tracing::warn! and return Ok(()), so the TS-side void is safe.

2. Unnecessary Promise.resolve() wrap

promise is already a Promise<T>; wrapping it with Promise.resolve(promise) adds an extra microtask tick for no reason. promise.then(() => null) is sufficient.

3. Pre-existing: misleading log message in register_task

In actor_context.rs:639, inside the register_task body, the log reads "actor keep_awake promise rejected". It should say "actor register_task promise rejected". Not introduced by this PR, but easy to fix in the same change.


What's working well

  • The core semantics are correct. keep_awake in rivetkit-core directly increments/decrements sleep_keep_awake_count via a RAII guard, which is the right primitive to use here.
  • Removing the isClosedTaskRegistrationError swallow is appropriate: keep_awake in core has no "closed" state, so the counter is always valid to increment.
  • The TypeScript-side contract (keepAwake<T> returns the original Promise<T> unchanged) is preserved correctly.
  • The index.d.ts type declaration is correctly added.

Test coverage

No new tests cover the native-path keepAwake behavior. The existing rivetkit-core Rust tests (e.g. sleep_shutdown_waits_for_keep_awake_work_then_finishes_next_tick) verify the core guard semantics, but there are no driver-level integration tests that exercise the NAPI bridge path specifically - e.g. asserting the actor stays alive while a c.keepAwake(promise) is in flight. Worth adding a driver test before merging.

@NathanFlurry NathanFlurry force-pushed the sleep-cleanup/06-ts-deprecate-prevent-sleep branch from dfa956c to 181bb0f Compare April 24, 2026 13:16
@NathanFlurry NathanFlurry force-pushed the sleep-cleanup/07-keep-awake-native-api branch from b27b338 to 0454dc5 Compare April 24, 2026 13:16
@github-actions
Copy link
Copy Markdown
Contributor

Preview packages published to npm

Install with:

npm install rivetkit@pr-4748

All packages published as 0.0.0-pr.4748.d1a6ff3 with tag pr-4748.

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-d1a6ff3
docker pull rivetdev/engine:full-d1a6ff3
Individual packages
npm install rivetkit@pr-4748
npm install @rivetkit/react@pr-4748
npm install @rivetkit/rivetkit-napi@pr-4748
npm install @rivetkit/workflow-engine@pr-4748

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