Skip to content

Commit 027f083

Browse files
committed
refactor(rivetkit-core): rename StopReason to ShutdownKind and kill enum fallthroughs
1 parent 297aa8b commit 027f083

13 files changed

Lines changed: 153 additions & 111 deletions

File tree

CLAUDE.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,10 @@ When the user asks to track something in a note, store it in `.agent/notes/` by
398398
- Do not use em dashes (—). Use periods to separate sentences instead.
399399
- Documenting deltas is not important or useful. A developer who has never worked on the project will not gain extra information if you add a comment stating that something was removed or changed because they don't know what was there before. The only time you would be adding a comment for something NOT being there is if its unintuitive for why its not there in the first place.
400400

401+
### Match statements
402+
403+
- Never use a `_ =>` fall-through arm when matching on a Rust enum (or a TypeScript discriminated union). Enumerate every variant explicitly so adding a new variant later is a compile error instead of a silent behavior change. `_` is fine for `Result`, `Option`, integers, strings, and other open value spaces. `_ => unreachable!()` / `_ => panic!()` are explicit asserts and acceptable.
404+
401405
## Documentation
402406

403407
- If you need to look at the documentation for a package, visit `https://docs.rs/{package-name}`. For example, serde docs live at `https://docs.rs/serde/`.

rivetkit-rust/packages/rivetkit-core/src/actor/context.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -669,13 +669,13 @@ impl ActorContext {
669669

670670
pub(crate) fn record_shutdown_wait(
671671
&self,
672-
reason: crate::actor::task_types::StopReason,
672+
reason: crate::actor::task_types::ShutdownKind,
673673
duration: Duration,
674674
) {
675675
self.0.metrics.observe_shutdown_wait(reason, duration);
676676
}
677677

678-
pub(crate) fn record_shutdown_timeout(&self, reason: crate::actor::task_types::StopReason) {
678+
pub(crate) fn record_shutdown_timeout(&self, reason: crate::actor::task_types::ShutdownKind) {
679679
self.0.metrics.inc_shutdown_timeout(reason);
680680
}
681681

rivetkit-rust/packages/rivetkit-core/src/actor/messages.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};
66

77
use crate::actor::connection::ConnHandle;
88
use crate::actor::lifecycle_hooks::Reply;
9-
use crate::actor::task_types::StopReason;
9+
use crate::actor::task_types::ShutdownKind;
1010
use crate::error::ProtocolError;
1111
use crate::types::ConnId;
1212
use crate::websocket::WebSocket;
@@ -308,7 +308,7 @@ pub enum ActorEvent {
308308
reply: Reply<Vec<StateDelta>>,
309309
},
310310
RunGracefulCleanup {
311-
reason: StopReason,
311+
reason: ShutdownKind,
312312
reply: Reply<()>,
313313
},
314314
DisconnectConn {
@@ -349,8 +349,8 @@ impl ActorEvent {
349349
SerializeStateReason::Inspector => "serialize_state_inspector",
350350
},
351351
Self::RunGracefulCleanup { reason, .. } => match reason {
352-
StopReason::Sleep => "run_sleep_cleanup",
353-
StopReason::Destroy => "run_destroy_cleanup",
352+
ShutdownKind::Sleep => "run_sleep_cleanup",
353+
ShutdownKind::Destroy => "run_destroy_cleanup",
354354
},
355355
Self::DisconnectConn { .. } => "disconnect_conn",
356356
#[cfg(test)]

rivetkit-rust/packages/rivetkit-core/src/actor/metrics.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use prometheus::{
99
Opts, Registry, TextEncoder,
1010
};
1111

12-
use crate::actor::task_types::{StateMutationReason, StopReason, UserTaskKind};
12+
use crate::actor::task_types::{ShutdownKind, StateMutationReason, UserTaskKind};
1313

1414
#[derive(Clone)]
1515
pub(crate) struct ActorMetrics {
@@ -216,7 +216,7 @@ impl ActorMetrics {
216216
for reason in StateMutationReason::ALL {
217217
state_mutation_total.with_label_values(&[reason.as_metric_label()]);
218218
}
219-
for reason in [StopReason::Sleep, StopReason::Destroy] {
219+
for reason in [ShutdownKind::Sleep, ShutdownKind::Destroy] {
220220
shutdown_wait_seconds.with_label_values(&[reason.as_metric_label()]);
221221
shutdown_timeout_total.with_label_values(&[reason.as_metric_label()]);
222222
}
@@ -397,7 +397,7 @@ impl ActorMetrics {
397397
.observe(duration.as_secs_f64());
398398
}
399399

400-
pub(crate) fn observe_shutdown_wait(&self, reason: StopReason, duration: Duration) {
400+
pub(crate) fn observe_shutdown_wait(&self, reason: ShutdownKind, duration: Duration) {
401401
let Some(inner) = self.inner.as_ref().as_ref() else {
402402
return;
403403
};
@@ -407,7 +407,7 @@ impl ActorMetrics {
407407
.observe(duration.as_secs_f64());
408408
}
409409

410-
pub(crate) fn inc_shutdown_timeout(&self, reason: StopReason) {
410+
pub(crate) fn inc_shutdown_timeout(&self, reason: ShutdownKind) {
411411
let Some(inner) = self.inner.as_ref().as_ref() else {
412412
return;
413413
};

rivetkit-rust/packages/rivetkit-core/src/actor/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,4 @@ pub use task::{
3737
ActionDispatchResult, ActorTask, DispatchCommand, HttpDispatchResult, LifecycleCommand,
3838
LifecycleEvent, LifecycleState,
3939
};
40-
pub use task_types::{ActorChildOutcome, StateMutationReason, StopReason, UserTaskKind};
40+
pub use task_types::{ActorChildOutcome, ShutdownKind, StateMutationReason, UserTaskKind};

rivetkit-rust/packages/rivetkit-core/src/actor/task.rs

Lines changed: 42 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ use crate::actor::state::{
6262
LAST_PUSHED_ALARM_KEY, PERSIST_DATA_KEY, PersistedActor, decode_last_pushed_alarm,
6363
decode_persisted_actor,
6464
};
65-
use crate::actor::task_types::StopReason;
65+
use crate::actor::task_types::ShutdownKind;
6666
use crate::error::{ActorLifecycle as ActorLifecycleError, ActorRuntime};
6767
use crate::types::{SaveStateOpts, format_actor_key};
6868
use crate::websocket::WebSocket;
@@ -96,7 +96,7 @@ static SHUTDOWN_CLEANUP_HOOK: OnceLock<Mutex<Option<ShutdownCleanupHook>>> = Onc
9696
pub(crate) struct ShutdownCleanupHookGuard;
9797

9898
#[cfg(test)]
99-
type ShutdownReplyHook = Arc<dyn Fn(&ActorContext, StopReason) + Send + Sync>;
99+
type ShutdownReplyHook = Arc<dyn Fn(&ActorContext, ShutdownKind) + Send + Sync>;
100100

101101
#[cfg(test)]
102102
// Forced-sync: test hooks are installed and cleared from synchronous guard APIs.
@@ -149,7 +149,7 @@ impl Drop for ShutdownReplyHookGuard {
149149
}
150150

151151
#[cfg(test)]
152-
fn run_shutdown_reply_hook(ctx: &ActorContext, reason: StopReason) {
152+
fn run_shutdown_reply_hook(ctx: &ActorContext, reason: ShutdownKind) {
153153
let hook = SHUTDOWN_REPLY_HOOK
154154
.get_or_init(|| Mutex::new(None))
155155
.lock()
@@ -164,7 +164,7 @@ pub enum LifecycleCommand {
164164
reply: oneshot::Sender<Result<()>>,
165165
},
166166
Stop {
167-
reason: StopReason,
167+
reason: ShutdownKind,
168168
reply: oneshot::Sender<Result<()>>,
169169
},
170170
FireAlarm {
@@ -184,7 +184,8 @@ impl LifecycleCommand {
184184
fn stop_reason(&self) -> Option<&'static str> {
185185
match self {
186186
Self::Stop { reason, .. } => Some(shutdown_reason_label(*reason)),
187-
_ => None,
187+
Self::Start { .. } => None,
188+
Self::FireAlarm { .. } => None,
188189
}
189190
}
190191
}
@@ -340,13 +341,13 @@ impl LifecycleEvent {
340341
}
341342

342343
enum LiveExit {
343-
Shutdown { reason: StopReason },
344+
Shutdown { reason: ShutdownKind },
344345
Terminated,
345346
}
346347

347348
struct SleepGraceState {
348349
deadline: Instant,
349-
reason: StopReason,
350+
reason: ShutdownKind,
350351
}
351352

352353
struct PersistedStartup {
@@ -686,7 +687,7 @@ impl ActorTask {
686687
}
687688

688689
#[cfg(test)]
689-
async fn handle_stop(&mut self, reason: StopReason) -> Result<()> {
690+
async fn handle_stop(&mut self, reason: ShutdownKind) -> Result<()> {
690691
let (reply_tx, reply_rx) = oneshot::channel();
691692
self.register_shutdown_reply("stop", Some(shutdown_reason_label(reason)), reply_tx);
692693
self.begin_grace(reason).await;
@@ -747,7 +748,7 @@ impl ActorTask {
747748

748749
async fn begin_stop(
749750
&mut self,
750-
reason: StopReason,
751+
reason: ShutdownKind,
751752
command: &'static str,
752753
command_reason: Option<&'static str>,
753754
reply: oneshot::Sender<Result<()>>,
@@ -811,7 +812,7 @@ impl ActorTask {
811812
}
812813
}
813814

814-
async fn begin_grace(&mut self, reason: StopReason) {
815+
async fn begin_grace(&mut self, reason: ShutdownKind) {
815816
tracing::debug!(
816817
actor_id = %self.ctx.actor_id(),
817818
reason = shutdown_reason_label(reason),
@@ -821,17 +822,18 @@ impl ActorTask {
821822
self.ctx.cancel_local_alarm_timeouts();
822823
self.ctx.set_local_alarm_callback(None);
823824
self.transition_to(match reason {
824-
StopReason::Sleep => LifecycleState::SleepGrace,
825-
StopReason::Destroy => LifecycleState::DestroyGrace,
825+
ShutdownKind::Sleep => LifecycleState::SleepGrace,
826+
ShutdownKind::Destroy => LifecycleState::DestroyGrace,
826827
});
827828
self.start_grace(reason);
828829
self.emit_grace_events(reason);
829830
}
830831

831-
fn emit_grace_events(&mut self, reason: StopReason) {
832+
fn emit_grace_events(&mut self, reason: ShutdownKind) {
832833
let conns: Vec<_> = self.ctx.conns().collect();
833834
for conn in conns {
834-
let hibernatable_sleep = matches!(reason, StopReason::Sleep) && conn.is_hibernatable();
835+
let hibernatable_sleep =
836+
matches!(reason, ShutdownKind::Sleep) && conn.is_hibernatable();
835837
if hibernatable_sleep {
836838
self.ctx.request_hibernation_transport_save(conn.id());
837839
continue;
@@ -1435,10 +1437,10 @@ impl ActorTask {
14351437
self.ctx.configure_actor_events(None);
14361438
}
14371439

1438-
fn start_grace(&mut self, reason: StopReason) {
1440+
fn start_grace(&mut self, reason: ShutdownKind) {
14391441
let grace_period = match reason {
1440-
StopReason::Sleep => self.factory.config().effective_sleep_grace_period(),
1441-
StopReason::Destroy => self.factory.config().effective_on_destroy_timeout(),
1442+
ShutdownKind::Sleep => self.factory.config().effective_sleep_grace_period(),
1443+
ShutdownKind::Destroy => self.factory.config().effective_on_destroy_timeout(),
14421444
};
14431445
self.sleep_deadline = None;
14441446
self.ctx.cancel_sleep_timer();
@@ -1466,7 +1468,13 @@ impl ActorTask {
14661468
None
14671469
}
14681470
LifecycleState::SleepGrace | LifecycleState::DestroyGrace => self.try_finish_grace(),
1469-
_ => None,
1471+
// Pre-startup, post-finalize, and tear-down states intentionally
1472+
// drop activity signals: there is no sleep deadline to reset and no
1473+
// grace window left to advance.
1474+
LifecycleState::Loading
1475+
| LifecycleState::SleepFinalize
1476+
| LifecycleState::Destroying
1477+
| LifecycleState::Terminated => None,
14701478
}
14711479
}
14721480

@@ -1532,7 +1540,7 @@ impl ActorTask {
15321540
#[cfg(test)]
15331541
async fn drain_tracked_work(
15341542
&mut self,
1535-
reason: StopReason,
1543+
reason: ShutdownKind,
15361544
phase: &'static str,
15371545
deadline: Instant,
15381546
) -> bool {
@@ -1542,7 +1550,7 @@ impl ActorTask {
15421550
#[cfg(test)]
15431551
async fn drain_tracked_work_with_ctx(
15441552
ctx: ActorContext,
1545-
reason: StopReason,
1553+
reason: ShutdownKind,
15461554
phase: &'static str,
15471555
deadline: Instant,
15481556
) -> bool {
@@ -1617,7 +1625,7 @@ impl ActorTask {
16171625
});
16181626
}
16191627

1620-
fn deliver_shutdown_reply(&mut self, reason: StopReason, result: &Result<()>) {
1628+
fn deliver_shutdown_reply(&mut self, reason: ShutdownKind, result: &Result<()>) {
16211629
#[cfg(test)]
16221630
run_shutdown_reply_hook(&self.ctx, reason);
16231631

@@ -1637,21 +1645,21 @@ impl ActorTask {
16371645
);
16381646
}
16391647

1640-
async fn run_shutdown(&mut self, reason: StopReason) -> Result<()> {
1648+
async fn run_shutdown(&mut self, reason: ShutdownKind) -> Result<()> {
16411649
self.sleep_grace = None;
16421650
let started_at = Instant::now();
16431651
self.state_save_deadline = None;
16441652
self.inspector_serialize_state_deadline = None;
16451653
self.sleep_deadline = None;
16461654
self.transition_to(match reason {
1647-
StopReason::Sleep => LifecycleState::SleepFinalize,
1648-
StopReason::Destroy => LifecycleState::Destroying,
1655+
ShutdownKind::Sleep => LifecycleState::SleepFinalize,
1656+
ShutdownKind::Destroy => LifecycleState::Destroying,
16491657
});
16501658
self.save_final_state().await?;
16511659
self.close_actor_event_channel();
16521660
self.join_aborted_run_handle().await;
16531661
Self::finish_shutdown_cleanup_with_ctx(self.ctx.clone(), reason).await?;
1654-
if matches!(reason, StopReason::Destroy) {
1662+
if matches!(reason, ShutdownKind::Destroy) {
16551663
self.ctx.mark_destroy_completed();
16561664
}
16571665
self.ctx.record_shutdown_wait(reason, started_at.elapsed());
@@ -1700,7 +1708,10 @@ impl ActorTask {
17001708
self.ctx.save_state(deltas).await
17011709
}
17021710

1703-
async fn finish_shutdown_cleanup_with_ctx(ctx: ActorContext, reason: StopReason) -> Result<()> {
1711+
async fn finish_shutdown_cleanup_with_ctx(
1712+
ctx: ActorContext,
1713+
reason: ShutdownKind,
1714+
) -> Result<()> {
17041715
let reason_label = shutdown_reason_label(reason);
17051716
let actor_id = ctx.actor_id().to_owned();
17061717
ctx.teardown_sleep_state().await;
@@ -1747,7 +1758,7 @@ impl ActorTask {
17471758
// Match the reference TS runtime: keep the persisted engine alarm armed
17481759
// across sleep so the next instance still has a wake trigger, but abort
17491760
// the local Tokio timer owned by the shutting-down instance.
1750-
StopReason::Sleep => {
1761+
ShutdownKind::Sleep => {
17511762
ctx.cancel_local_alarm_timeouts();
17521763
tracing::debug!(
17531764
actor_id = %actor_id,
@@ -1756,7 +1767,7 @@ impl ActorTask {
17561767
"actor shutdown cleanup step completed"
17571768
);
17581769
}
1759-
StopReason::Destroy => {
1770+
ShutdownKind::Destroy => {
17601771
ctx.cancel_driver_alarm_logged();
17611772
tracing::debug!(
17621773
actor_id = %actor_id,
@@ -2106,10 +2117,10 @@ impl ActorTask {
21062117
}
21072118
}
21082119

2109-
fn shutdown_reason_label(reason: StopReason) -> &'static str {
2120+
fn shutdown_reason_label(reason: ShutdownKind) -> &'static str {
21102121
match reason {
2111-
StopReason::Sleep => "sleep",
2112-
StopReason::Destroy => "destroy",
2122+
ShutdownKind::Sleep => "sleep",
2123+
ShutdownKind::Destroy => "destroy",
21132124
}
21142125
}
21152126

rivetkit-rust/packages/rivetkit-core/src/actor/task_types.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,16 @@ pub enum LifecycleState {
1515
}
1616

1717
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18-
pub enum StopReason {
18+
pub enum ShutdownKind {
1919
Sleep,
2020
Destroy,
2121
}
2222

23-
impl StopReason {
23+
impl ShutdownKind {
2424
pub(crate) fn as_metric_label(self) -> &'static str {
2525
match self {
26-
StopReason::Sleep => "sleep",
27-
StopReason::Destroy => "destroy",
26+
ShutdownKind::Sleep => "sleep",
27+
ShutdownKind::Destroy => "destroy",
2828
}
2929
}
3030
}

rivetkit-rust/packages/rivetkit-core/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ pub use actor::task::{
3131
ActionDispatchResult, ActorTask, DispatchCommand, HttpDispatchResult, LifecycleCommand,
3232
LifecycleEvent, LifecycleState,
3333
};
34-
pub use actor::task_types::StopReason;
34+
pub use actor::task_types::ShutdownKind;
3535
pub use error::ActorLifecycle;
3636
pub use inspector::{Inspector, InspectorSnapshot};
3737
pub use registry::{CoreRegistry, ServeConfig};

0 commit comments

Comments
 (0)