tdd


Prestart being called after failure with stopping strategy


I'm creating retry/reconnect functionality for a actor that is on a remote service. The actor should on prestart call the selection reference to subscribe to messages from the actor on the remote service. If for some reason the actor is not there I want my actor to retry a couple of times before reporting a failure to connect.
I'm using the TestKit to tdd the functionality. The problem I'm running into is that when the actor throws the timeout exception prestart is called afterwards even though I have a stop strategy.
I'm I missunderstanding the lifecycle of the actor? Seems wierd that PreStart is called if the strategy is to stop after failure.
public class MyActor : ReceiveActor
{
private readonly ActorPath path;
private ActorSelection selection;
private int retry = 0;
protected override void PreStart()
{
selection = Context.ActorSelection(path);
selection.Tell("prestart");
SetReceiveTimeout(TimeSpan.FromSeconds(1));
}
public MyActor(ActorPath path)
{
this.path = path;
Receive<ReceiveTimeout>(timeout =>
{
if (retry < 2)
{
retry++;
selection.Tell("retry");
return;
}
throw new Exception("timeout");
});
}
}
public class Test : TestKit
{
[Fact]
public void FactMethodName()
{
var probe = CreateTestProbe();
var props = Props.Create(() => new MyActor(probe.Ref.Path))
.WithSupervisorStrategy(new OneForOneStrategy(exception => Directive.Stop));
Sys.ActorOf(props);
//Initial
probe.ExpectMsg<string>(s => s=="prestart",TimeSpan.FromSeconds(2));
//Retries
probe.ExpectMsg<string>(s => s == "retry", TimeSpan.FromSeconds(2));
probe.ExpectMsg<string>(s => s == "retry", TimeSpan.FromSeconds(2));
//No more
probe.ExpectNoMsg( TimeSpan.FromSeconds(10));
}
}
My Solution after answer from Jeff
public class ParentActor : UntypedActor
{
private readonly Func<IUntypedActorContext, IActorRef> creation;
private IActorRef actorRef;
public ParentActor(Func<IUntypedActorContext, IActorRef> creation)
{
this.creation = creation;
}
protected override void PreStart()
{
actorRef = creation(Context);
}
protected override void OnReceive(object message)
{
actorRef.Tell(message);
}
}
public class MyActor : ReceiveActor
{
private readonly ActorPath path;
private int retry;
private ActorSelection selection;
public MyActor(ActorPath path)
{
this.path = path;
Receive<ReceiveTimeout>(timeout =>
{
if (retry < 2)
{
retry++;
selection.Tell("retry");
return;
}
throw new Exception("timeout");
});
}
protected override void PreStart()
{
selection = Context.ActorSelection(path);
selection.Tell("prestart");
SetReceiveTimeout(TimeSpan.FromSeconds(1));
}
}
public class Test : TestKit
{
[Fact]
public void FactMethodName()
{
var probe = CreateTestProbe();
var props = Props.Create(
() => new ParentActor(context => context.ActorOf(Props.Create(
() => new MyActor(probe.Ref.Path), null), "myactor")))
.WithSupervisorStrategy(new OneForOneStrategy(exception => Directive.Stop));
Sys.ActorOf(props);
//Initial
probe.ExpectMsg<string>(s => s == "prestart", TimeSpan.FromSeconds(2));
//Retries
probe.ExpectMsg<string>(s => s == "retry", TimeSpan.FromSeconds(2));
probe.ExpectMsg<string>(s => s == "retry", TimeSpan.FromSeconds(2));
//No more
probe.ExpectNoMsg(TimeSpan.FromSeconds(10));
}
}
Works but feels like it could be a part of the TestKit to beable set supervisor strategy for the guardian of the test
var props = Props.Create(() => new MyActor(probe.Ref.Path))
.WithSupervisorStrategy(new OneForOneStrategy(exception => Directive.Stop));
This set the supervisor strategy for MyActor, it will be used for MyActor's children and not for MyActor itself.
Sys.ActorOf(props);
This is creating MyActor under the /user guardian which have a OneForOne Restart directive by default. This is why your actor is restarting.
To get what you want, you need to create a parent actor with the custom supervisor strategy and create MyActor under it.

Related Links

Why we should start with a failing test in TDD?
TDD is applicable all the time? [closed]
Avoiding code duplication when defining Gherkin Given and When statements
Guard : phpunit is not installed on your machine
How to write User Stories for technical implementation details?
Test Driven Development process
The following setups were not matched - converting JustMock to Moq
Fitnesse ScenarioLibrary is not being included in the tests
How to TDD a 2-steps process which requires input from a remote party?
What are the guiding principles when practicing TDD? [closed]
TDD: refactoring and global regressions
Cucumber capybara fill_in failing
Applying TDD in Spikes
Test rig in TDD (test driven development)
TDD: Test first or Repository pattern first
Installing phpunit to a Laravel 4 site

Categories

HOME
heroku
pycharm
lodash
vmware
adb
razor
disassembler
applepay
numeral.js
timeout
flask-wtforms
ups
saxon
transformation
invantive-sql
one-hot-encoding
pass-by-reference
bootstrap-tour
wijmo
blazemeter
crystal-reports-2010
pepper
semantic-analysis
intel-pin
assistant
bluestacks
xquery-3.0
ioio
catch-all
nssegmentedcontrol
automake
gesture
az-application-insights
dynamic-reports
botbuilder
firebase-admin
outlook-api
eclipse-gef
thin
wptoolkit
avconv
flickr-api
xml-documentation
python-c-api
celery-task
domain-model
crypt
android-cursor
flutterwave
time-and-attendance
color-picker
libpng
slicknav
dstu2-fhir
file-writing
phishing
nsfilemanager
whois
ptrace
iad
rtbkit
ios8-today-widget
icu4j
iis-arr
browser-bugs
drawbitmap
deis
oberon
sonarqube5.1.2
npapi
nstableviewcell
id3v2
wordpress-theme-customize
rdl
openexr
wp-query
braille
jquery-mobile-dialog
trusted
cascalog
viewswitcher
code-cleanup
bigcouch
libc++
vdsp
xmemcached
xdomainrequest
floating
createwindow
gamequery
xsdobjectgen
vc90
audio-capture
virtual-functions

Resources

Database Users
RDBMS discuss
Database Dev&Adm
javascript
java
csharp
php
android
javascript
java
csharp
php
python
android
jquery
ruby
ios
html
Mobile App
Mobile App
Mobile App