I'm trying to figure out how to model the state of a remote "IoT" device with a persistent-actor, for example:
The user wants to turn on a light so we do the most logical.
User sends OnCommand
the persistent actor receives the command, generates a LightTurnedOnEvent and updates its state to on
So that makes sense but the problem here is the light is actually never turned on. Ok so then we build a LightControlActor that knows low level hardware-controll voodoo. This actor listen for LightTurnedOnEvent and when it gets it it does it thing and turnes on the light.
Awsome now we have a light turned on! But not happy. LightTurnedOnEvent is kind of lying here, the light is not turned on yet. Following this logic LightTurnedOnEvent should be generated by the LightControlActor and my persistent actor should generate some SentRequestToTurnOnLight but now this gets complicated for me with all the different semantics.
User sends OnCommand
Persistent actor recivecs OnCommand generate RequestedLightTurnOnEvent and set state to pending.
LightController picks up on the RequestedLightTurnOnEvent and tries to turn on the light on the external system.
So then what? Now how do I update the state of the persistent actor? Have the LightController send some veird command SetStateToOnCommand?
So how do I update the persistent state when the light is actually turned on?
One idea is to go with something like "saga" for your events.
LightController: State idle
lightController ! OnCommand
persist(LightTurnOnAttempted)
lightControl ! LightTurnOnCommand
become(pending)
LightControl:
lightControl ! LightTurnOnCommand
performLightTurnOnAsyncFunction.map(_ => TurnOnLightCommand) pipeTo lightController
LightController: State pending
lightController ! TurnOnLightCommand
persist(LightTurnedOn)
become(initialized)
This gives you fine grained control. In case of crash and during the process of recovery, you can check whether the light was turned on or the LightController was in pending state. If it was in pending state, you can resend the LightTurnOnCommand.
But you never know for sure that the light turned on, even if the HW controller says so, i.e. the bulb could be damaged.
The idea with events is the implications that they have in their bounded context. In your case, LightTurnedOnEvent is owned by the persistent actor and it has a strict meaning only in its context. From the owner actor's POV the light should be ON and a future TurnOnCommand would not change this state, a new event would not be emitted (it's idempotent).
If you want this event to have other implications, you need a Saga (or whatever you want to call it) that would react to this event and will send another command to another actor, in another context, i.e. in the HW context. This HW actor would emit its own events, relevant only in its context, i.e. LightBulbCoupledToPowerSource or something like this; it could even be named LightTurnedOnEvent, like the other, but in a separate namespace, very likely with other properties.
To better see this separation of concerns/contexts, we can imagine a situation in which a Saga, in reaction to LightTurnedOnEvent would send 3 commands to 3 different Light bulbs, in a big room for example.
Related
The following is how I create a behavior:
Behaviors.setup(ctx => {
ctx.system.receptionist ! Receptionist.Register(serviceKey, ctx.self)
Behaviors.withTimers[Request](scheduler => {
ctx.self ! Msg1 // Not sure if this is related to this question
scheduler.startTimerWithFixedDelay(Msg2, 1.hour)
new MyExtensionOfAbstractBehavior(ctx,scheduler)
})
})
Now I would like to add supervision. To keep it simple I want SupervisorStrategy.resume or SupervisorStrategy.restart. But I don't know how to add that supervision. I know the following code will compile. But I am not sure that is the right approach.
Behaviors.supervise[Request]( ... every thing in the previous code ...)
.onFailure(SupervisorStrategy.resume)
When an actor restarts or resumes its behavior, it won't get deregistered in receptionist (is that true?). So I should not re-register the actor every time it restarts or resumes its behavior.
I have a similar problem with the scheduler. I don't know if I have to make sure Behaviors.withTimers gets re-executed or not upon restart/ resume.
On restart or resumption, the actor is, to the outside world, still the same actor, so I probably wouldn't wrap receptionist registration with supervise. As for the timers, I think the question is whether you want to reset the timers: if you do, then wrap withTimers in supervise.
I'm simulating a security control process, and i can't do that each passenger pickup their baggage. I have tried with Match, Combine, Pickup, but I still can't execute the commands correctly.
I've created the follow flowchart, and the problem is in the wReclaimPax, pickup and wReclaimBags blocks (you can see them in the picture).
https://ibb.co/v3V57Tm
I saw this link Anylogic - Combined multiple items back to original owner to understand something, but I still need help.
I've created 3 functions:
isMatch:
if(equipaje.pasajeroLink.equals(pasajero.equipajeLink)){
return true;
}
return false;
paxBags:
for(int i=0;i<wait.size();i++){
Pasajero p=(Pasajero)wait.get(i);
if(isMatch(p,bag))
return p;
}
return null;
bagsPax:
for(int i=0;i<wait.size();i++){
Equipaje e=(Equipaje)wait.get(i);
if(isMatch(pasajero,e))
return e;
}
return null;
Assumed context
You haven't really explained how your code is related to your process but I'm assuming the following:
Because this is luggage-retrieval, you want to ensure that a passenger
agent (Pasajero) only enters the Pickup block (representing taking bag from
carousel) when his bag (Equipaje agent by the look of it) has
arrived into the wReclaimBag Wait, and been released from it to
queue4 Queue.
For this you need triggers (to remove agents from Wait blocks) when
either a passenger (Pasajero) arrives in wReclaimPax Wait, or a bag (Equipaje) arrives
in the wReclaimBag Wait (because you don't know whether the passenger or their bag will get to their respective Wait blocks first).
So your paxBags function is called in on-entry action of the wReclaimBag Wait, and your bagsPax function in the on-entry action of the wReclaimPax Wait.
Possible problems with current approach
Without knowing more of your model it's hard to say but problems I can think of based on what you've supplied are:
Your functions return the Pasajero or Equipaje if there is one that matches. Your match check relies seemingly on bidirectional connections (links) between Pasajero and Equipaje. Obviously if they're not setup properly the model won't work and, if you're using bidirectional connections you shouldn't need to check both ends.
Your functions need calling so that, if they return non null, they then free the matching agent from the other Wait block, and free themselves. Are you doing that? Without checking, there may be issues with calling free for yourself as you enter a Wait block (since this kind of depends on AnyLogic internals as to whether you count as being 'in' the block at this stage and can be freed). If this seems to be the problem you could create a timeout 0 dynamic event instance to do the free so that you're not doing it within the scope of the on-enter action.
Your pickup block (since it's been setup so that the entering agent will always want to pickup the first agent (Equipaje) in queue4) just needs to be set as waiting for quantity 1 (though see below).
If you've done all this the most likely problem is that the underlying events ordering of AnyLogic is affecting things. When you free agents I'm fairly sure the freeing actually happens in a timeout 0 event scheduled under-the-covers. So it may be that the passenger arrives at the Pickup before their Equipment arrives in queue4 though, if you set the Pickup to be "Exact quantity (wait for)", with quantity of 1, it should handle that.
The animation of the process (numbers in/out/within each block and details when clicking on blocks) should also help you debug what is going wrong; e.g., are bags being left in the Wait when they should have been released, etc.
P.S. With this kind of thing you should always create a minimal example model to make testing the issue/solution easier (and for sharing in help forums such as this where the rest of the complexity of your model is irrelevant). Often you find the problem 'naturally' in the process of trying to construct such a model that reproduces your problem in a minimal way.
I've read scala-best-practices and have a question about "5.2. SHOULD mutate state in actors only with context.become". I don't understand why it is so bad to store internal state using var. If actor executes all messages sequentially I just can't see any source of problems. What do I miss?
Consider the first example in the article that you referenced:
class MyActor extends Actor {
val isInSet = mutable.Set.empty[String]
def receive = {
case Add(key) =>
isInSet += key
case Contains(key) =>
sender() ! isInSet(key)
}
}
There's nothing inherently incorrect with this example, so there isn't some vital understanding that you're missing. As you know, an actor processes the messages in its mailbox sequentially, so it is safe to represent its state in an internal variable and to mutate this state, as long as the actor doesn't expose that state1.
become is often used to dynamically switch an actor's behavior (e.g., changing the kind of messages that the actor handles) and/or its state. In the second example in the article, the actor's state is encoded in its behavior as a parameter. This is an elegant alternative to the first example, but in this simple case it's a matter of preference.
One scenario in which become can really shine, however, is an actor that has many state transitions. Without the use of become, the actor's logic in its receive block can grow unmanageably large or turn into a jungle of if-else statements. As an example of using become to model state transitions, check out this sample project that models the "Dining Philosophers" problem.
1A potential issue is that while isInSet is a val, it's a mutable Set, so weird things can happen if the actor exposes this state to something outside of the actor itself (which it is not doing in the example). For example, if the actor sends this Set in a message to another actor, then the external actor can change this state, causing unexpected behavior or race conditions. One can mitigate this issue by changing the val to a var, and the mutable Set to an immutable Set.
I don't think there's necessarily anything wrong with using vars in actors, for exactly the reasons you mentioned (Keep in mind though, that this is only for code executed in the context of the receive(...), i.e., if you start a thread, or use a Future, even if it's from within the receive, that code is no longer executed sequentially).
However, I personally prefer to use context.become(...) for controlling state, mainly because it clearly shows me the states in the actor that can change (vars can be scattered all over).
I also prefer to limit it to 0 or 1 call to context.become(...) per message handled, so it's clear where this state transition is happening.
That said, you can get the same benefits by using a convention where you define all your vars in one place, and make sure to re-assign them in one place (say towards the end) in your message handling.
I have a working JavaFX application. It has three main parts:
A list of signals visible globally to the entire application. Each signal has a String value property that is observable. This list is instantiated before the JavaFX scene is constructed, the signal list constructor is run in the Application FX thread.
A JavaFX table implemented as an Observable Array List so that as signal values change they are automatically updated on the GUI.
A simulation engine that runs a loop that changes signal values. This loop is run in a worker thread.
I am fully aware that GUI elements like selection lists, text in boxes, etc. can only be updated in the Application FX thread. I use Platform.runLater(someRunnableThing) to do that. However, what blindsided me was that even changing a signal value, which changes the value of the observable String property, must be done in the FX thread or not-in-Application-FX-thread exceptions will be thrown.
Curiously the application still works fine despite these exceptions, because eventually (instantaneously to a human observer) the changed value is picked up and displayed. I only noticed this when doing final checks of run-time behavior before release.
It is a very common thing for a worker thread to be changing variables in the background while a GUI is displaying information based on the changing variables. Platform.runLater() is expensive and somewhat non-deterministic. Since the worker thread is not touching the GUI and the application FX thread can choose to grab updates whenever it wants it seems draconian to me for Java to force this behavior.
Have I missed something about modifying observed properties? Any thoughts and ideas appreciated.
There are no rules about updating JavaFX properties from background threads. The only rule is that you cannot update nodes that are part of a scene graph from a background thread, and there are no plans (and likely never will be) to relax that rule.
You didn't post any code, so we can only make educated guesses as to what the actual problem is. What is likely happening is that you have a listener or a binding on one of the properties (or observable collections) that is being changed from your background thread, where the listener/binding is updating the UI. Listeners with observables (including listeners created and registered by bindings) are, of course, invoked on the same thread on which the observable is changed.
So if you have something like
someApplicationProperty.addListener((obs, oldValue, newValue) -> {
someUIElement.setSomeValue(...);
});
or perhaps
someUIElement.someProperty().bind(someApplicationProperty);
just replace it with
someApplicationProperty.addListener((obs, oldValue, newValue) -> {
Platform.runLater(() -> someUIElement.setSomeValue(...));
});
In other words, you can continue to update your application properties from the background thread, as long as your listener updates the UI from the FX Application Thread.
In the case where the listener is registered by the UI component itself, you must ensure that the observable with which the listener is registered is changed on the UI thread. This is the case in the example you allude to, for example updating the backing list for a ListView or TableView. You can do this either by directly invoking Platform.runLater(), or by placing a layer in between the model and the UI. For the latter approach, see Correct Way to update Observable List from background thread
Also maybe see http://www.oracle.com/technetwork/articles/java/javafxinteg-2062777.html
I have a doubt whether the code in the "onTransition" block (akka FSM) is executed after the new state is reached? or before the new state is reached.
The articles and book I've read mentions the word "during"... which (to me) suggests "before the new state is reached".
Does it really matter?
I guess so... I mean, changing to a new state implies (in most cases) changing the state data. Usually we would change that state data in the event handler (in the "when-case-event" block).
But what if the new state depends on the outcome of calculations / actions performed in the "onTransition" block? In that case, we will have to move that block into the "when-case-event" block.
So, it's not clear for me now...: is there any rule / guidance: what actions should go into the "when-case-event", and what actions should go into the "onTransition"?
addition: I hope in the next revision of Akka Doc, some kind of clarification / guidance on this topic would be included.
Thanks in advance,
Raka
In onTransition the old state data is available via stateData, and the new state data is available as nextStateData. The new state cannot be changed by onTransition, but you can send a message to self.