From ae09be095abfa71c22cf0454aaf915a4f85c38e4 Mon Sep 17 00:00:00 2001 From: Nathan Flurry Date: Mon, 4 May 2026 00:59:57 -0700 Subject: [PATCH] fix(rivetkit): make duplicate sleep requests idempotent --- .../packages/rivetkit-core/src/actor/context.rs | 3 +-- .../rivetkit/tests/driver/actor-sleep-db.test.ts | 16 +++++----------- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/rivetkit-rust/packages/rivetkit-core/src/actor/context.rs b/rivetkit-rust/packages/rivetkit-core/src/actor/context.rs index b5fa769213..35d69c4254 100644 --- a/rivetkit-rust/packages/rivetkit-core/src/actor/context.rs +++ b/rivetkit-rust/packages/rivetkit-core/src/actor/context.rs @@ -412,8 +412,7 @@ impl ActorContext { }; } if self.0.sleep_requested.swap(true, Ordering::SeqCst) { - return Err(ActorLifecycleError::Stopping.build()) - .context("sleep already requested for this generation"); + return Ok(()); } self.cancel_sleep_timer(); if Handle::try_current().is_ok() { diff --git a/rivetkit-typescript/packages/rivetkit/tests/driver/actor-sleep-db.test.ts b/rivetkit-typescript/packages/rivetkit/tests/driver/actor-sleep-db.test.ts index 75a424831c..9708b62689 100644 --- a/rivetkit-typescript/packages/rivetkit/tests/driver/actor-sleep-db.test.ts +++ b/rivetkit-typescript/packages/rivetkit/tests/driver/actor-sleep-db.test.ts @@ -776,8 +776,7 @@ describeDriverMatrix("Actor Sleep Db", (driverTestConfig) => { expect(events).toContain("waituntil-after-reject"); }); - // TODO(#4705): Root-cause duplicate sleep-call semantics and re-enable this coverage. - test.skip("double sleep call is a no-op", async (c) => { + test("double sleep call is a no-op", async (c) => { const { client } = await setupDriverTest(c, driverTestConfig); // Use a connection to send the sleep trigger, because @@ -790,15 +789,10 @@ describeDriverMatrix("Actor Sleep Db", (driverTestConfig) => { await waitForConnectionReady(connection); - // Trigger sleep twice rapidly via the connection. - // The second call should be a no-op because - // #sleepCalled is already true. - await connection.triggerSleep(); - try { - await connection.triggerSleep(); - } catch { - // May throw if actor already stopping - } + // Trigger sleep twice from the same action invocation. The second + // call should be a no-op because the first call already requested + // sleep for this actor generation. + await connection.triggerSleepTwice(); // Wait for sleep to complete await waitFor(driverTestConfig, 1500);