Skip to content

Async actor lifecycle handlers (PostStop, PreStart, etc.) #8036

@Aaronontheweb

Description

@Aaronontheweb

Summary

Currently actor lifecycle methods (PreStart, PostStop, PreRestart, PostRestart) are synchronous. This makes it awkward to handle async cleanup in PostStop when an actor has pending state to flush.

Current Workaround

protected override void PostStop()
{
    if (_pendingDelta != 0)
    {
        try
        {
            // Forced to block on async operation
            _store.UpdateAsync(_pendingDelta)
                .GetAwaiter().GetResult();
        }
        catch (Exception ex)
        {
            Context.GetLogger().Error(ex, "Failed to flush");
        }
    }
    base.PostStop();
}

This works but:

  • Blocks a thread during shutdown
  • Feels wrong in an async-first codebase
  • Easy to accidentally fire-and-forget (which loses data)

Proposed API

protected override async Task PostStopAsync()
{
    if (_pendingDelta != 0)
    {
        await _store.UpdateAsync(_pendingDelta);
    }
    await base.PostStopAsync();
}

The actor system would await these during the stop sequence.

Use Cases

  • Flushing buffered writes to database before passivation
  • Graceful disconnect from external services
  • Async resource cleanup

Questions

  • Would this require changes to the mailbox/dispatcher?
  • Should this be opt-in (new base class) or added to ReceiveActor/UntypedActor?
  • Any concerns about deadlocks during coordinated shutdown?

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions