These are chat archives for petabridge/akka-bootcamp

12th
Aug 2015
Alan Rutter
@AlanGRutter
Aug 12 2015 00:28

Been going through the bootcamp and started experimenting but not getting expected results. I have the following two actors

  public class ApplicationActor : UntypedActor
    {
        private int count = 0;
        private ICancelable cancellation;
        private IActorRef _coordinator;

         public ApplicationActor(IActorRef coordinator)
        {
            _coordinator = coordinator;
        }

        protected override void PreStart()
        {
            Console.WriteLine("Prestart called!");

            count = 0;
            cancellation = Context.System.Scheduler.ScheduleTellRepeatedlyCancelable(
                TimeSpan.FromMilliseconds(500), TimeSpan.FromMilliseconds(5000), Self, "check", Self);

        }

        protected override void PreRestart(Exception reason, object message)
        {
            Console.WriteLine("PreRestart called!");
        }

        protected override void PostStop()
        {
            Console.WriteLine("PostStop called!");

            cancellation.Cancel();
            Context.System.Scheduler.ScheduleTellOnce(TimeSpan.FromSeconds(1), _coordinator, "stopped", ActorRefs.Nobody);
            base.PostStop();
        }

        protected override void OnReceive(object message)
        {
            count++;
            Console.WriteLine("Count = {0}", count);

            if (count > 2)
                _coordinator.Tell("shutdown");
        }
    }

    public class ApplicationCoordinatorActor : ReceiveActor
    {
        IActorRef _applicationActor;

        public ApplicationCoordinatorActor()
        {
            Stopped();
        }

        private void Started()
        {
            Console.WriteLine("Coordinator started");

            Receive<string>(s => s.Equals("shutdown"), s =>
            {
                Context.Stop(_applicationActor);
            });

            Receive<string>(s => s.Equals("stopped"), s =>
            {
                Become(Stopped);
            });
        }

        private void Stopped()
        {
            Console.WriteLine("Coordinator stopped");

            _applicationActor = Context.ActorOf(Props.Create(() => new ApplicationActor(Self)), "Application");
            Become(Started);
        }
    }

The aim is for the child actor to signal the coordinator which then stops the child. This works fine the first time, but after the child is restarted, it just keeps going and the coordinator never receives another shutdown message. I've probably done something really stupid but I just can't see it.

Alan Rutter
@AlanGRutter
Aug 12 2015 01:28
I'm actually researching this so I can employ it on a real project which is along the same lines as @mclark1129 is working on. I need to deal with stock market orders and real-time pricing updates - not sure where to start at the moment. Maybe this topic would make a good a blog article/tutorial as it is quite common.
Aaron Stannard
@Aaronontheweb
Aug 12 2015 01:30
@AlanGRutter we just published this case study about 5 minutes ago that might be of interest: https://petabridge.com/blog/akkadotnet-goes-to-wall-street/
Alan Rutter
@AlanGRutter
Aug 12 2015 01:31
Superb timing - I'll take a look. Any ideas on my issue from above? Something definitely odd happening.
Aaron Stannard
@Aaronontheweb
Aug 12 2015 01:31
taking a look at it now
so you never receive a second "shutdown" message?
do you see Prestart called appear on the console?
after you recreate the child?
Alan Rutter
@AlanGRutter
Aug 12 2015 01:36
How do I send an image?
Here's the output on the console:
Coordinator stopped
Coordinator started
Prestart called!
Count = 1
Count = 2
Count = 3
PostStop called!
Coordinator stopped
Coordinator started
Prestart called!
Count = 1
Count = 2
Count = 3
Count = 4
Count = 5
...
Aaron Stannard
@Aaronontheweb
Aug 12 2015 01:39
ok, got it
I think I know what the issue is
try changing the Stopped method to this
Alan Rutter
@AlanGRutter
Aug 12 2015 01:39
Bet I'm being really stupid!
Aaron Stannard
@Aaronontheweb
Aug 12 2015 01:40
private void Stopped()
        {
            Console.WriteLine("Coordinator stopped");
            var self = Self;
            _applicationActor = Context.ActorOf(Props.Create(() => new ApplicationActor(self)), "Application");
            Become(Started);
        }
nah, this is a subtle problem
but give that a try and see if it works
Alan Rutter
@AlanGRutter
Aug 12 2015 01:40
Trying it now!
Nope - same result!
Aaron Stannard
@Aaronontheweb
Aug 12 2015 01:42
darn - well at least that wasn't the issue
would have thrown off a lot of the assumptions I've made about how C#'s compiler works if that were the case :p
Alan Rutter
@AlanGRutter
Aug 12 2015 01:43
Yeah - thought I was getting the hang of this but now I'm a bit stumped.
Aaron Stannard
@Aaronontheweb
Aug 12 2015 01:46
hmmm, why don't you put a logging statement inside Receive<string>(s => s.Equals("shutdown"),
see if that's getting called
that can help us eliminate a few issues
Alan Rutter
@AlanGRutter
Aug 12 2015 01:46
What I'm really trying out here is how to stop a child actor so I can restart it. I'm developing an app that talks to an external app via COM libraries. When I instantiate a class, the external app fires up, then I need to log in etc - if the app gets closed, it sends an event which I trap. Then I need to restart the external app.
Ok will do.
Aaron Stannard
@Aaronontheweb
Aug 12 2015 01:46
What I'm really trying out here is how to stop a child actor so I can restart it
Ah, best way to do that is just throw an exception
the default SupervisorStrategy will automatically restart the actor
but now I want to know why this wasn't working :p
Alan Rutter
@AlanGRutter
Aug 12 2015 01:49
Guess I was trying to be clean and not throw an exception. My statement was logged the first time, but not afterwards. If I put a breakpoint on the _coordinator.Tell("shutdown") line, it gets hit - the message doesn't ever arrive though.
Aaron Stannard
@Aaronontheweb
Aug 12 2015 01:50
let's try not giving your ApplicationActor a name
change it to _applicationActor = Context.ActorOf(Props.Create(() => new ApplicationActor(self)),);
errr
_applicationActor = Context.ActorOf(Props.Create(() => new ApplicationActor(Self)));
Alan Rutter
@AlanGRutter
Aug 12 2015 01:51
Still not working.
Aaron Stannard
@Aaronontheweb
Aug 12 2015 01:52
other thing you can try is not using behavior-switching
the ReceiveActor does all sorts of insane caching in order to stay performant
Alan Rutter
@AlanGRutter
Aug 12 2015 01:53
Ok - hang on. I'll need to re-write it a bit.
Aaron Stannard
@Aaronontheweb
Aug 12 2015 01:58
yeah this is a weird one
not sure what's going on exactly
Alan Rutter
@AlanGRutter
Aug 12 2015 01:59

I changed the code to:

public class ApplicationCoordinatorActor : UntypedActor
    {
        IActorRef _applicationActor;

        protected override void OnReceive(object message)
        {
            if (message.Equals("shutdown")) {
                Console.WriteLine("Shutdown received.");
                Context.Stop(_applicationActor);

            } else if (message.Equals("stopped")) {
                Console.WriteLine("Stopped received");
                _applicationActor = Context.ActorOf(Props.Create(() => new ApplicationActor(Self)));
            }
        }
    }

and placed a .Tell("stopped") after creating the coordinator.

This works fine. Question is why doesn't it work with ReceiveActor - is this a bug?

Aaron Stannard
@Aaronontheweb
Aug 12 2015 01:59
could be
basically, how I would rewrite your code
 public class ApplicationCoordinatorActor : ReceiveActor
    {
        IActorRef _applicationActor;

        public ApplicationCoordinatorActor()
        {
           Started();
        }

        private void Started()
        {
            Console.WriteLine("Coordinator started");

            Receive<string>(s => s.Equals("shutdown"), s =>
            {
                Context.Stop(_applicationActor);
            });

            Receive<string>(s => s.Equals("stopped"), s =>
            {
               Stopped();
            });
        }

        private void Stopped()
        {
            Console.WriteLine("Coordinator stopped");

            _applicationActor = Context.ActorOf(Props.Create(() => new ApplicationActor(Self)), "Application");
        }
    }
what it looked like to me was that the _applicationActor got cached
and never got dirtied
so I'm wondering if some of the intelligence built into the ReceiveActor (for performance purposes)
accidentally mucked up what occured inside your Stopped statement, since that's a behavior
and typically all you define inside behaviors are Receives
not so much procedural code that's intended to be run
Alan Rutter
@AlanGRutter
Aug 12 2015 02:04
Just tried your code and that also works. So was I doing it wrong - or is there a bug.
Aaron Stannard
@Aaronontheweb
Aug 12 2015 02:04
why not both? :p
I didn't write any of the optimization code for ReceiveActor so I'm not sure
but that doesn't look right to me
Alan Rutter
@AlanGRutter
Aug 12 2015 02:06
It's a bit off-putting when learning something new - what I was trying to do made sense to me. But basically a behaviour should only have Receives
Aaron Stannard
@Aaronontheweb
Aug 12 2015 02:06
yeah, what I meant was that the fact that the ReceiveActorworked that way is weird
I wouldn't expect that either if I were you
Alan Rutter
@AlanGRutter
Aug 12 2015 02:07
Is it something that you can log to be investigated along with my non-working code.
... and for getting an actor to restart, I should just throw a deliberate exception.
Aaron Stannard
@Aaronontheweb
Aug 12 2015 02:10
@AlanGRutter akkadotnet/akka.net#1238
logged it
pinged the guys who wrote it
in general though, behaviors should only have receives
although in areas where I use behavior switching you'll often see me use transition methods like this: https://github.com/petabridge/akkadotnet-code-samples/blob/master/Cluster.WebCrawler/src/WebCrawler.Service/Actors/ApiMaster.cs#L138
where I do state cleanup / unstash messages and that sort of thing
but yeah, to restart an actor
throw an exception
Alan Rutter
@AlanGRutter
Aug 12 2015 02:14
Thanks for your help - I'll continue experimenting. Still got a few bootcamp lessons to go.
Roger Johansson
@rogeralsing
Aug 12 2015 08:25
:+1: on the "BecomReady" approach
Aaron Stannard
@Aaronontheweb
Aug 12 2015 18:14
@/all doing our virtual Akka.NET meetup live via Google Hangouts and YouTube in 15 minutes! https://petabridge.com/blog/akkadotnet-virtual-meetup/ - the broadcast will be recorded and published on our YouTube channel once the livestream is over: https://www.youtube.com/c/PetabridgeAcademy
Andrew Skotzko
@skotzko
Aug 12 2015 18:35
@/all we’re live everyone! https://www.youtube.com/watch?v=YuY1ziEqifU