Skip to content

Commit d1acd40

Browse files
committed
Add API for UntypedActorWithStash types
1 parent bd276df commit d1acd40

File tree

5 files changed

+110
-12
lines changed

5 files changed

+110
-12
lines changed

docs/articles/actors/untyped-actor-api.md

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -708,18 +708,16 @@ static void Main(string[] args)
708708

709709
## Stash
710710

711-
The `IWithStash` interface enables an actor to temporarily stash away messages that can not or should not be handled using the actor's current behavior. Upon changing the actor's message handler, i.e., right before invoking `Context.Become()` or `Context.Unbecome()`, all stashed messages can be "un-stashed", thereby prepending them to the actor's mailbox. This way, the stashed messages can be processed in the same order as they have been received originally.
711+
The `UntypedActorWithStash` class enables an actor to temporarily stash away messages that can not or should not be handled using the actor's current behavior. Upon changing the actor's message handler, i.e., right before invoking `Context.Become()` or `Context.Unbecome()`, all stashed messages can be "un-stashed", thereby prepending them to the actor's mailbox. This way, the stashed messages can be processed in the same order as they have been received originally. An actor that extends `UntypedActorWithStash` will automatically get a deque-based mailbox.
712712

713713
> [!NOTE]
714-
> The interface `IWithStash` implements the marker interface `IRequiresMessageQueue<DequeBasedMessageQueueSemantics>` which requests the system to automatically choose a deque-based mailbox implementation for the actor (defaults to an unbounded deque mailbox). If you want more control over the mailbox, see the documentation on mailboxes: [Mailboxes](xref:mailboxes).
714+
> The abstract class `UntypedActorWithStash` implements the marker interface `IRequiresMessageQueue<DequeBasedMessageQueueSemantics>` which requests the system to automatically choose a deque-based mailbox implementation for the actor. If you want more control over the mailbox, see the documentation on mailboxes: [Mailboxes](xref:mailboxes).
715715
716-
Here is an example of the `IWithStash` interface in action:
716+
Here is an example of the `UntypedActorWithStash` interface in action:
717717

718718
```csharp
719-
public class ActorWithProtocol : UntypedActor, IWithStash
719+
public class ActorWithProtocol : UntypedActor, UntypedActorWithStash
720720
{
721-
public IStash Stash { get; set; }
722-
723721
protected override void OnReceive(object message)
724722
{
725723
switch (message)
@@ -755,14 +753,10 @@ Invoking `Stash()` adds the current message (the message that the actor received
755753

756754
Invoking `UnstashAll()` enqueues messages from the stash to the actor's mailbox until the capacity of the mailbox (if any) has been reached (note that messages from the stash are prepended to the mailbox). In case a bounded mailbox overflows, a `MessageQueueAppendFailedException` is thrown. The stash is guaranteed to be empty after calling `UnstashAll()`.
757755

758-
Note that the stash is part of the ephemeral actor state, unlike the mailbox. Therefore, it should be managed like other parts of the actor's state which have the same property.
759-
760-
However, the `IWithStash` interface implementation of `PreRestart` will call `UnstashAll()`. This means that before the actor restarts, it will transfer all stashed messages back to the actor’s mailbox.
761-
762-
The result of this is that when an actor is restarted, any stashed messages will be delivered to the new incarnation of the actor. This is usually the desired behavior.
756+
Note that the stash is part of the ephemeral actor state, unlike the mailbox. Therefore, it should be managed like other parts of the actor's state which have the same property. The `UntypedActorWithStash` implementation of `PreRestart` will call `UnstashAll()`, which is usually the desired behavior.
763757

764758
> [!NOTE]
765-
> If you want to enforce that your actor can only work with an unbounded stash, then you should use the `IWithUnboundedStash` interface instead.
759+
> If you want to enforce that your actor can only work with an unbounded stash, then you should use the `UntypedActorWithUnboundedStash ` class instead.
766760
767761
## Killing an Actor
768762

src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.Core.verified.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1864,6 +1864,21 @@ namespace Akka.Actor
18641864
protected void RunTask(System.Action action) { }
18651865
protected void RunTask(System.Func<System.Threading.Tasks.Task> action) { }
18661866
}
1867+
public abstract class UntypedActorWithStash : Akka.Actor.UntypedActor, Akka.Actor.IActorStash, Akka.Actor.IWithStash, Akka.Actor.IWithUnrestrictedStash, Akka.Dispatch.IRequiresMessageQueue<Akka.Dispatch.IDequeBasedMessageQueueSemantics>
1868+
{
1869+
protected UntypedActorWithStash() { }
1870+
public Akka.Actor.IStash Stash { get; set; }
1871+
}
1872+
public abstract class UntypedActorWithUnboundedStash : Akka.Actor.UntypedActor, Akka.Actor.IActorStash, Akka.Actor.IWithUnboundedStash, Akka.Actor.IWithUnrestrictedStash, Akka.Dispatch.IRequiresMessageQueue<Akka.Dispatch.IUnboundedDequeBasedMessageQueueSemantics>
1873+
{
1874+
protected UntypedActorWithUnboundedStash() { }
1875+
public Akka.Actor.IStash Stash { get; set; }
1876+
}
1877+
public abstract class UntypedActorWithUnrestrictedStash : Akka.Actor.UntypedActor, Akka.Actor.IActorStash, Akka.Actor.IWithUnrestrictedStash
1878+
{
1879+
protected UntypedActorWithUnrestrictedStash() { }
1880+
public Akka.Actor.IStash Stash { get; set; }
1881+
}
18671882
public delegate void UntypedReceive(object message);
18681883
public class static WrappedMessage
18691884
{

src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.DotNet.verified.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1866,6 +1866,21 @@ namespace Akka.Actor
18661866
protected void RunTask(System.Action action) { }
18671867
protected void RunTask(System.Func<System.Threading.Tasks.Task> action) { }
18681868
}
1869+
public abstract class UntypedActorWithStash : Akka.Actor.UntypedActor, Akka.Actor.IActorStash, Akka.Actor.IWithStash, Akka.Actor.IWithUnrestrictedStash, Akka.Dispatch.IRequiresMessageQueue<Akka.Dispatch.IDequeBasedMessageQueueSemantics>
1870+
{
1871+
protected UntypedActorWithStash() { }
1872+
public Akka.Actor.IStash Stash { get; set; }
1873+
}
1874+
public abstract class UntypedActorWithUnboundedStash : Akka.Actor.UntypedActor, Akka.Actor.IActorStash, Akka.Actor.IWithUnboundedStash, Akka.Actor.IWithUnrestrictedStash, Akka.Dispatch.IRequiresMessageQueue<Akka.Dispatch.IUnboundedDequeBasedMessageQueueSemantics>
1875+
{
1876+
protected UntypedActorWithUnboundedStash() { }
1877+
public Akka.Actor.IStash Stash { get; set; }
1878+
}
1879+
public abstract class UntypedActorWithUnrestrictedStash : Akka.Actor.UntypedActor, Akka.Actor.IActorStash, Akka.Actor.IWithUnrestrictedStash
1880+
{
1881+
protected UntypedActorWithUnrestrictedStash() { }
1882+
public Akka.Actor.IStash Stash { get; set; }
1883+
}
18691884
public delegate void UntypedReceive(object message);
18701885
public class static WrappedMessage
18711886
{

src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.Net.verified.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1864,6 +1864,21 @@ namespace Akka.Actor
18641864
protected void RunTask(System.Action action) { }
18651865
protected void RunTask(System.Func<System.Threading.Tasks.Task> action) { }
18661866
}
1867+
public abstract class UntypedActorWithStash : Akka.Actor.UntypedActor, Akka.Actor.IActorStash, Akka.Actor.IWithStash, Akka.Actor.IWithUnrestrictedStash, Akka.Dispatch.IRequiresMessageQueue<Akka.Dispatch.IDequeBasedMessageQueueSemantics>
1868+
{
1869+
protected UntypedActorWithStash() { }
1870+
public Akka.Actor.IStash Stash { get; set; }
1871+
}
1872+
public abstract class UntypedActorWithUnboundedStash : Akka.Actor.UntypedActor, Akka.Actor.IActorStash, Akka.Actor.IWithUnboundedStash, Akka.Actor.IWithUnrestrictedStash, Akka.Dispatch.IRequiresMessageQueue<Akka.Dispatch.IUnboundedDequeBasedMessageQueueSemantics>
1873+
{
1874+
protected UntypedActorWithUnboundedStash() { }
1875+
public Akka.Actor.IStash Stash { get; set; }
1876+
}
1877+
public abstract class UntypedActorWithUnrestrictedStash : Akka.Actor.UntypedActor, Akka.Actor.IActorStash, Akka.Actor.IWithUnrestrictedStash
1878+
{
1879+
protected UntypedActorWithUnrestrictedStash() { }
1880+
public Akka.Actor.IStash Stash { get; set; }
1881+
}
18671882
public delegate void UntypedReceive(object message);
18681883
public class static WrappedMessage
18691884
{
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
//-----------------------------------------------------------------------
2+
// <copyright file="UntypedActorWithStash.cs" company="Akka.NET Project">
3+
// Copyright (C) 2009-2022 Lightbend Inc. <http://www.lightbend.com>
4+
// Copyright (C) 2013-2022 .NET Foundation <https://github.com/akkadotnet/akka.net>
5+
// </copyright>
6+
//-----------------------------------------------------------------------
7+
8+
using Akka.Dispatch;
9+
10+
namespace Akka.Actor
11+
{
12+
/// <summary>
13+
/// Actor base class that should be extended to create an actor with a stash.
14+
/// <para>
15+
/// The stash enables an actor to temporarily stash away messages that can not or
16+
/// should not be handled using the actor's current behavior.
17+
/// </para>
18+
/// <para>
19+
/// Note that the subclasses of `UntypedActorWithStash` by default request a Deque based mailbox since this class
20+
/// implements the <see cref="IRequiresMessageQueue{T}"/> marker interface.
21+
/// </para>
22+
/// You can override the default mailbox provided when `IDequeBasedMessageQueueSemantics` are requested via config:
23+
/// <code>
24+
/// akka.actor.mailbox.requirements {
25+
/// "Akka.Dispatch.IDequeBasedMessageQueueSemantics" = your-custom-mailbox
26+
/// }
27+
/// </code>
28+
/// Alternatively, you can add your own requirement marker to the actor and configure a mailbox type to be used
29+
/// for your marker.
30+
/// <para>
31+
/// For a `Stash` based actor that enforces unbounded deques see <see cref="UntypedActorWithUnboundedStash"/>.
32+
/// There is also an unrestricted version <see cref="UntypedActorWithUnrestrictedStash"/> that does not
33+
/// enforce the mailbox type.
34+
/// </para>
35+
/// </summary>
36+
public abstract class UntypedActorWithStash : UntypedActor, IWithStash
37+
{
38+
public IStash Stash { get; set; }
39+
}
40+
41+
/// <summary>
42+
/// Actor base class with `Stash` that enforces an unbounded deque for the actor.
43+
/// See <see cref="UntypedActorWithStash"/> for details on how `Stash` works.
44+
/// </summary>
45+
public abstract class UntypedActorWithUnboundedStash : UntypedActor, IWithUnboundedStash
46+
{
47+
public IStash Stash { get; set; }
48+
}
49+
50+
/// <summary>
51+
/// Actor base class with `Stash` that does not enforce any mailbox type. The proper mailbox has to be configured
52+
/// manually, and the mailbox should extend the <see cref="IDequeBasedMessageQueueSemantics"/> marker interface.
53+
/// See <see cref="UntypedActorWithStash"/> for details on how `Stash` works.
54+
/// </summary>
55+
public abstract class UntypedActorWithUnrestrictedStash : UntypedActor, IWithUnrestrictedStash
56+
{
57+
public IStash Stash { get; set; }
58+
}
59+
}

0 commit comments

Comments
 (0)