@@ -295,13 +295,18 @@ pub async fn pegboard_actor(ctx: &mut WorkflowCtx, input: &Input) -> Result<()>
295295 return Ok ( Loop :: Continue ) ;
296296 }
297297
298+ let ( Some ( runner_id) , Some ( runner_workflow_id) ) = ( state. runner_id , state. runner_workflow_id ) else {
299+ tracing:: warn!( "actor not allocated, ignoring event" ) ;
300+ return Ok ( Loop :: Continue ) ;
301+ } ;
302+
298303 match sig. inner {
299304 protocol:: Event :: EventActorIntent ( protocol:: EventActorIntent {
300305 intent,
301306 ..
302307 } ) => match intent {
303308 protocol:: ActorIntent :: ActorIntentSleep => {
304- if let Some ( runner_workflow_id ) = state. runner_workflow_id {
309+ if ! state. sleeping {
305310 state. gc_timeout_ts =
306311 Some ( util:: timestamp:: now ( ) + ACTOR_STOP_THRESHOLD_MS ) ;
307312 state. sleeping = true ;
@@ -312,37 +317,35 @@ pub async fn pegboard_actor(ctx: &mut WorkflowCtx, input: &Input) -> Result<()>
312317 . await ?;
313318
314319 // Send signal to kill actor now that we know it will be sleeping
315- destroy:: kill (
316- ctx,
317- input. actor_id ,
318- state. generation ,
319- runner_workflow_id,
320- )
320+ ctx. signal ( crate :: workflows:: runner:: Command {
321+ inner : protocol:: Command :: CommandStopActor ( protocol:: CommandStopActor {
322+ actor_id : input. actor_id . to_string ( ) ,
323+ generation : state. generation ,
324+ } ) ,
325+ } )
326+ . to_workflow_id ( runner_workflow_id)
327+ . send ( )
321328 . await ?;
322- } else {
323- tracing:: warn!( "actor not allocated, ignoring sleep intent" ) ;
324329 }
325330 }
326331 protocol:: ActorIntent :: ActorIntentStop => {
327- if let Some ( runner_workflow_id) = state. runner_workflow_id {
328- state. gc_timeout_ts =
329- Some ( util:: timestamp:: now ( ) + ACTOR_STOP_THRESHOLD_MS ) ;
332+ state. gc_timeout_ts =
333+ Some ( util:: timestamp:: now ( ) + ACTOR_STOP_THRESHOLD_MS ) ;
330334
331- ctx. activity ( runtime:: SetNotConnectableInput {
332- actor_id : input. actor_id ,
333- } )
334- . await ?;
335+ ctx. activity ( runtime:: SetNotConnectableInput {
336+ actor_id : input. actor_id ,
337+ } )
338+ . await ?;
335339
336- destroy:: kill (
337- ctx,
338- input. actor_id ,
339- state. generation ,
340- runner_workflow_id,
341- )
342- . await ?;
343- } else {
344- tracing:: warn!( "actor not allocated, ignoring stop intent" ) ;
345- }
340+ ctx. signal ( crate :: workflows:: runner:: Command {
341+ inner : protocol:: Command :: CommandStopActor ( protocol:: CommandStopActor {
342+ actor_id : input. actor_id . to_string ( ) ,
343+ generation : state. generation ,
344+ } ) ,
345+ } )
346+ . to_workflow_id ( runner_workflow_id)
347+ . send ( )
348+ . await ?;
346349 }
347350 } ,
348351 protocol:: Event :: EventActorStateUpdate (
@@ -351,23 +354,19 @@ pub async fn pegboard_actor(ctx: &mut WorkflowCtx, input: &Input) -> Result<()>
351354 } ,
352355 ) => match actor_state {
353356 protocol:: ActorState :: ActorStateRunning => {
354- if let Some ( runner_id) = state. runner_id {
355- state. gc_timeout_ts = None ;
356-
357- ctx. activity ( runtime:: SetStartedInput {
358- actor_id : input. actor_id ,
359- } )
360- . await ?;
361-
362- ctx. msg ( Ready {
363- runner_id,
364- } )
365- . tag ( "actor_id" , input. actor_id )
366- . send ( )
367- . await ?;
368- } else {
369- tracing:: warn!( "actor not allocated, ignoring running event" ) ;
370- }
357+ state. gc_timeout_ts = None ;
358+
359+ ctx. activity ( runtime:: SetStartedInput {
360+ actor_id : input. actor_id ,
361+ } )
362+ . await ?;
363+
364+ ctx. msg ( Ready {
365+ runner_id,
366+ } )
367+ . tag ( "actor_id" , input. actor_id )
368+ . send ( )
369+ . await ?;
371370 }
372371 protocol:: ActorState :: ActorStateStopped (
373372 protocol:: ActorStateStopped { code, .. } ,
@@ -541,6 +540,19 @@ async fn handle_stopped(
541540 }
542541 }
543542
543+ // Kill old actor if lost (just in case it ended up allocating)
544+ if let ( true , Some ( old_runner_workflow_id) ) = ( lost, old_runner_workflow_id) {
545+ ctx. signal ( crate :: workflows:: runner:: Command {
546+ inner : protocol:: Command :: CommandStopActor ( protocol:: CommandStopActor {
547+ actor_id : input. actor_id . to_string ( ) ,
548+ generation : state. generation ,
549+ } ) ,
550+ } )
551+ . to_workflow_id ( old_runner_workflow_id)
552+ . send ( )
553+ . await ?;
554+ }
555+
544556 // Reschedule no matter what
545557 if force_reschedule {
546558 match runtime:: reschedule_actor ( ctx, & input, state, true ) . await ? {
@@ -566,18 +578,6 @@ async fn handle_stopped(
566578
567579 match ( input. crash_policy , failed) {
568580 ( CrashPolicy :: Restart , true ) => {
569- // Kill old actor immediately if lost
570- if lost {
571- destroy:: kill (
572- ctx,
573- input. actor_id ,
574- state. generation ,
575- old_runner_workflow_id
576- . context ( "should have runner_workflow_id set if not sleeping" ) ?,
577- )
578- . await ?;
579- }
580-
581581 match runtime:: reschedule_actor ( ctx, & input, state, false ) . await ? {
582582 runtime:: SpawnActorOutput :: Allocated { .. } => { }
583583 // NOTE: Its not possible for `SpawnActorOutput::Sleep` to be returned here, the crash
@@ -637,6 +637,11 @@ async fn handle_stopped(
637637 state. wake_for_alarm = false ;
638638 state. will_wake = false ;
639639
640+ ctx. msg ( Stopped { } )
641+ . tag ( "actor_id" , input. actor_id )
642+ . send ( )
643+ . await ?;
644+
640645 Ok ( None )
641646}
642647
@@ -653,6 +658,9 @@ pub struct Ready {
653658 pub runner_id : Id ,
654659}
655660
661+ #[ message( "pegboard_actor_stopped" ) ]
662+ pub struct Stopped { }
663+
656664#[ signal( "pegboard_actor_allocate" ) ]
657665#[ derive( Debug ) ]
658666pub struct Allocate {
0 commit comments