-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
293 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,31 +1,99 @@ | ||
** WRITING IN PROCESS ** | ||
|
||
## OnStart event | ||
|
||
- OnStart event is fired when actor starts or restarts right after PreStart or PostRestart | ||
- Following messages starts to be handled after finishing running OnStart. | ||
Actor has `PreStart` method for initializing itself on start. | ||
But this method should be synchronous so it's not good for an asynchronous one. | ||
To handle this, `OnStart` method is provided. | ||
|
||
#### OnStart when an actor starts | ||
|
||
`OnStart` event is fired when an actor starts or restarts right after `PreStart` or `PostRestart`, | ||
and further messages are pending until `OnStart` finishes. | ||
|
||
Following `MyActor` has `PreStart` and `OnStart` event handler. | ||
|
||
```csharp | ||
public class TestActor : InterfacedActor, IWorker | ||
class MyActor : InterfacedActor | ||
{ | ||
protected override void PreStart() | ||
override void PreStart() | ||
{ | ||
Console.WriteLine("PreStart()"); | ||
} | ||
|
||
protected override async Task OnStart(bool restarted) | ||
override async Task OnStart(bool restarted) | ||
{ | ||
Console.WriteLine("OnStart() Begin"); | ||
Console.WriteLine($"OnStart() Begin"); | ||
await Task.Delay(10); | ||
Console.WriteLine("OnStart() End"); | ||
Console.WriteLine($"OnStart() End"); | ||
} | ||
|
||
[MessageHandler] | ||
async Task Handle(string message) | ||
{ | ||
Console.WriteLine($"Handle({message}) Begin"); | ||
await Task.Delay(10); | ||
Console.WriteLine($"Handle({message}) End"); | ||
} | ||
} | ||
``` | ||
|
||
You can see event order. | ||
|
||
```csharp | ||
var actor = System.ActorOf<TestActor>(); | ||
var actor = System.ActorOf<MyActor>(); | ||
actor.Tell("Test"); | ||
// Output: | ||
// PreStart() | ||
// OnStart() Begin | ||
// OnStart() End | ||
// Handle(Test) Begin | ||
// Handle(Test) End | ||
``` | ||
|
||
#### OnStart when an actor restarts | ||
|
||
`OnStart` is also fired when an actor restarts. | ||
`restarted` tells whether it is starting or restarting. | ||
|
||
```csharp | ||
class MyActor2 : InterfacedActor | ||
{ | ||
override void PreStart() | ||
{ | ||
Console.WriteLine("PreStart()"); | ||
} | ||
|
||
override void PostRestart(Exception cause) | ||
{ | ||
Console.WriteLine($"PostRestart({cause.GetType().Name})"); | ||
} | ||
|
||
override async Task OnStart(bool restarted) | ||
{ | ||
Console.WriteLine($"OnStart({restarted}) Begin"); | ||
await Task.Delay(10); | ||
Console.WriteLine($"OnStart({restarted}) End"); | ||
} | ||
|
||
[MessageHandler] | ||
async Task Handle(string message) | ||
{ | ||
Console.WriteLine($"Handle({message}) Throw"); | ||
throw new InvalidOperationException(message); | ||
} | ||
} | ||
``` | ||
|
||
`Handle(Test)` throws an unhandled exception and causes an actor to restart. | ||
|
||
```csharp | ||
var actor = _system.ActorOf<MyActor2>(); | ||
actor.Tell("Test"); | ||
// Output: | ||
// PreStart() | ||
// OnStart(False) Begin | ||
// OnStart(False) End | ||
// Handle(Test) Throw | ||
// PostRestart(AggregateException) | ||
// OnStart(True) Begin | ||
// OnStart(True) End | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,33 +1,63 @@ | ||
** WRITING IN PROCESS ** | ||
|
||
## Stop an actor and OnGracefulStop event | ||
|
||
- To stop an interfaced actor gracefully, send `InterfacedPoisonPill`. | ||
- When an actor receives `InterfacedPoisonPill`, stop receiving further messages and waits until all handler finish. | ||
- If an actor stops not by `InterfacedPoisonPill`, OnGracefulStop is not called. | ||
There are a few ways to stop an actor. If you are not familar this topic, read | ||
[How to Stop an Actor... the Right Way](https://petabridge.com/blog/how-to-stop-an-actor-akkadotnet/) first. | ||
|
||
Stopping an interfaced actor gracefully, you need to send `InterfacedPoisonPill` | ||
message to an actor instead of `PoisonPill`. When an actor receives | ||
`InterfacedPoisonPill`, | ||
|
||
- Stops receiving further messages. | ||
- Waits for running reentrant handlers completed. | ||
- Executes `OnGracefulStop` method. | ||
|
||
```csharp | ||
public class TestActor : InterfacedActor, IWorker | ||
class MyActor : InterfacedActor | ||
{ | ||
protected override async Task OnGracefulStop() | ||
[MessageHandler, Reentrant] | ||
async Task Handle(string message) | ||
{ | ||
Console.WriteLine($"Handle({message}) Begin"); | ||
await Task.Delay(10); | ||
Console.WriteLine($"Handle({message}) End"); | ||
} | ||
|
||
override async Task OnGracefulStop() | ||
{ | ||
Console.WriteLine("OnGracefulStop() Begin"); | ||
await Task.Delay(10); | ||
Console.WriteLine("OnGracefulStop() End"); | ||
} | ||
|
||
protected override void PostStop() | ||
override void PostStop() | ||
{ | ||
Console.WriteLine("PostStop()"); | ||
} | ||
} | ||
``` | ||
|
||
You can see event order. | ||
|
||
```csharp | ||
var actor = ActorOf<TestActor>(); | ||
actor.Tell("Test"); | ||
actor.Tell(InterfacedPoisonPill.Instance); | ||
// Output: | ||
// Handle(Test) Begin | ||
// Handle(Test) End | ||
// OnGracefulStop() Begin | ||
// OnGracefulStop() End | ||
// PostStop() | ||
``` | ||
|
||
But if you send `PoisonPill` to an interfaced actor, it halts reentrant handlers | ||
and doesn't execute `OnGracefulStop` because it cannot recognize these things. | ||
|
||
```csharp | ||
var actor = ActorOf<TestActor>(); | ||
actor.Tell("Test"); | ||
actor.Tell(PoisonPill.Instance); | ||
// Output: | ||
// Handle(Test) Begin | ||
// PostStop() | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Threading.Tasks; | ||
using Akka.Interfaced; | ||
using Akka.Actor; | ||
|
||
namespace Manual | ||
{ | ||
public class DemoFilter | ||
{ | ||
private ActorSystem _system; | ||
|
||
public DemoFilter(ActorSystem system, string[] args) | ||
{ | ||
_system = system; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Threading.Tasks; | ||
using Akka.Interfaced; | ||
using Akka.Actor; | ||
|
||
namespace Manual | ||
{ | ||
public class DemoLogFilter | ||
{ | ||
private ActorSystem _system; | ||
|
||
public DemoLogFilter(ActorSystem system, string[] args) | ||
{ | ||
_system = system; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Threading.Tasks; | ||
using Akka.Interfaced; | ||
using Akka.Actor; | ||
|
||
namespace Manual | ||
{ | ||
public class DemoStartEvent | ||
{ | ||
private ActorSystem _system; | ||
|
||
public DemoStartEvent(ActorSystem system, string[] args) | ||
{ | ||
_system = system; | ||
} | ||
|
||
public class MyActor : InterfacedActor | ||
{ | ||
protected override void PreStart() | ||
{ | ||
Console.WriteLine("PreStart()"); | ||
} | ||
|
||
protected override async Task OnStart(bool restarted) | ||
{ | ||
Console.WriteLine($"OnStart() Begin"); | ||
await Task.Delay(10); | ||
Console.WriteLine($"OnStart() End"); | ||
} | ||
|
||
[MessageHandler] | ||
protected async Task Handle(string message) | ||
{ | ||
Console.WriteLine($"Handle({message}) Begin"); | ||
await Task.Delay(10); | ||
Console.WriteLine($"Handle({message}) End"); | ||
} | ||
} | ||
|
||
private async Task DemoOnStart() | ||
{ | ||
var actor = _system.ActorOf<MyActor>(); | ||
actor.Tell("Test"); | ||
await actor.GracefulStop(TimeSpan.FromMinutes(1), InterfacedPoisonPill.Instance); | ||
} | ||
|
||
public class MyActor2 : InterfacedActor | ||
{ | ||
protected override void PreStart() | ||
{ | ||
Console.WriteLine("PreStart()"); | ||
} | ||
|
||
protected override void PostRestart(Exception cause) | ||
{ | ||
Console.WriteLine($"PostRestart({cause.GetType().Name})"); | ||
} | ||
|
||
protected override async Task OnStart(bool restarted) | ||
{ | ||
Console.WriteLine($"OnStart({restarted}) Begin"); | ||
await Task.Delay(10); | ||
Console.WriteLine($"OnStart({restarted}) End"); | ||
} | ||
|
||
[MessageHandler] | ||
protected async Task Handle(string message) | ||
{ | ||
Console.WriteLine($"Handle({message}) Throw"); | ||
throw new InvalidOperationException(message); | ||
} | ||
} | ||
|
||
private async Task DemoRestart() | ||
{ | ||
var actor = _system.ActorOf<MyActor2>(); | ||
actor.Tell("Test"); | ||
await actor.GracefulStop(TimeSpan.FromMinutes(1), InterfacedPoisonPill.Instance); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Threading.Tasks; | ||
using Akka.Interfaced; | ||
using Akka.Actor; | ||
|
||
namespace Manual | ||
{ | ||
public class DemoStopActor | ||
{ | ||
private ActorSystem _system; | ||
|
||
public DemoStopActor(ActorSystem system, string[] args) | ||
{ | ||
_system = system; | ||
} | ||
|
||
public class MyActor : InterfacedActor | ||
{ | ||
[MessageHandler, Reentrant] | ||
private async Task Handle(string message) | ||
{ | ||
Console.WriteLine($"Handle({message}) Begin"); | ||
await Task.Delay(10); | ||
Console.WriteLine($"Handle({message}) End"); | ||
} | ||
|
||
protected override async Task OnGracefulStop() | ||
{ | ||
Console.WriteLine("OnGracefulStop() Begin"); | ||
await Task.Delay(10); | ||
Console.WriteLine("OnGracefulStop() End"); | ||
} | ||
|
||
protected override void PostStop() | ||
{ | ||
Console.WriteLine("PostStop()"); | ||
} | ||
} | ||
|
||
private async Task DemoInterfacedPoisonPill() | ||
{ | ||
var actor = _system.ActorOf<MyActor>(); | ||
actor.Tell("Test"); | ||
await actor.GracefulStop(TimeSpan.FromMinutes(1), InterfacedPoisonPill.Instance); | ||
} | ||
|
||
private async Task DemoPoisonPill() | ||
{ | ||
var actor = _system.ActorOf<MyActor>(); | ||
actor.Tell("Test"); | ||
await actor.GracefulStop(TimeSpan.FromMinutes(1), PoisonPill.Instance); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters