Skip to content

Commit

Permalink
Manuals: Start, Stop event. #9
Browse files Browse the repository at this point in the history
  • Loading branch information
veblush committed Jun 3, 2016
1 parent b9f14bd commit 518270a
Show file tree
Hide file tree
Showing 7 changed files with 293 additions and 18 deletions.
88 changes: 78 additions & 10 deletions docs/StartEvent.md
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
```
46 changes: 38 additions & 8 deletions docs/StopActor.md
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()
```
18 changes: 18 additions & 0 deletions samples/Manual/Program/DemoFilter.cs
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;
}
}
}
18 changes: 18 additions & 0 deletions samples/Manual/Program/DemoLogFilter.cs
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;
}
}
}
82 changes: 82 additions & 0 deletions samples/Manual/Program/DemoStartEvent.cs
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);
}
}
}
55 changes: 55 additions & 0 deletions samples/Manual/Program/DemoStopActor.cs
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);
}
}
}
4 changes: 4 additions & 0 deletions samples/Manual/Program/Manual.Program.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,14 @@
<ItemGroup>
<Compile Include="DemoActor.cs" />
<Compile Include="DemoException.cs" />
<Compile Include="DemoFilter.cs" />
<Compile Include="DemoLogFilter.cs" />
<Compile Include="DemoMessageHandler.cs" />
<Compile Include="DemoObserver.cs" />
<Compile Include="DemoReentrantHandler.cs" />
<Compile Include="DemoRunTask.cs" />
<Compile Include="DemoStartEvent.cs" />
<Compile Include="DemoStopActor.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
Expand Down

0 comments on commit 518270a

Please sign in to comment.