I want my FSM to terminate any time event doesn't come after specified amout of time in every state.
I can achieve such a scenario only in case there is no event after FSM creation by specifing timeout value in init callback, but I would like to have this functionality working for all of the states as well.
Any easy & quick solution?
Best Regards
Matt
You can set timeout in return tuple in each state {next_state, NextStateName, NewStateData, Timeout}. See gen_fsm documentation for more details. But it works only for case there is not any incoming messages in gen_fsm so it is suitable only if for example you would like terminate process when probably nobody is communicating with it. If you would like hard limits (for protocols for example) you should use erlang:send_after/3 or erlang:start_timer/3 and handle also timer termination and so.
Related
I'm using grpc in iOS with bidirectional streams.
For the stream that I write to, I subclassed GRXWriter and I'm writing to it from a background thread.
I want to be as quick as possible. However, I see that GRXWriter's status switches between started and paused, and I sometimes get an exception when I write to it during the paused state. I found that before writing, I have to wait for GRXWriter.state to become started. Is this really a requirement? Is GRXWriter only allowed to write when its state is started? It switches very often between started and paused, and this feels like it may be slowing me down.
Another issue with this state check is that my code looks ugly. Is there any other way that I can use bidirectional streams in a nicer way? In C# grpc, I just get a stream that I write freely to.
Edit: I guess the reason I'm asking is this: in my thread that writes to GRXWriter, I have a while loop that keeps checking whether state is started and does nothing if it is not. Is there a better way to do this rather than polling the state?
The GRXWriter pauses because the gRPC Core only accepts one write operation pending at a time. The next one has to wait until the first one completes. So the GRPCCall instance will block the writer until the previous write is completed, by modifying its state!
In terms of the exception, I am not sure why you are getting the problem. GRXWriter is more like an abstract class and it seems you did your own implementation by inheriting from it. If you really want to do so, it might be helpful to refer to GRXBufferedPipe, which is an internal implementation. In particular, if you want to avoid waiting in a loop for writing, writing again in the setter of GRXWriter's state should be a good option.
I'm writing an Erlang application that requires actively polling some remote resources, and I want the process that does the polling to fit into the OTP supervision trees and support all the standard facilities like proper termination, hot code reloading, etc.
However, the two default behaviours, gen_server and gen_fsm seem to only support operation based on callbacks. I could abuse gen_server to do that through calls to self or abuse gen_fsm by having a single state that always loops to itself with a timeout 0, but I'm not sure that's safe (i.e. doesn't exhaust the stack or accumulate unread messages in the mailbox).
I could make my process into a special process and write all that handling myself, but that effectively makes me reimplement the Erlang equivalent of the wheel.
So is there a behavior for code like this?
loop(State) ->
do_stuff(State), % without waiting to be called
loop(NewState).
And if not, is there a safe way to trick default behaviours into doing this without exhausting the stack or accumulating messages over time or something?
The standard way of doing that in Erlang is by using erlang:send_after/3. See this SO answer and also this example implementation.
Is it possible that you could employ an essentially non OTP compliant process? Although to be a good OTP citizen, you do ideally want to make your long running processes into gen_server's and gen_fsm's, sometimes you have to look beyond the standard issue rule book and consider why the rules exist.
What if, for example, your supervisor starts your gen_server, and your gen_server spawns another process (lets call it the active_poll process), and they link to each other so that they have shared fate (if one dies the other dies). The active_poll process is now indirectly supervised by the supervisor that spawned the gen_server, because if it dies, so will the gen_server, and they will both get restarted. The only problem you really have to solve now is code upgrade, but this is not too difficult - your gen_server gets a code_change callback call when the code is to be upgraded, and it could simply send a message to the active_poll process, which can make an appropriate fully qualified function call, and bingo, it's running the new code.
If this doesn't suit you for some reason and/or you MUST use gen_server/gen_fsm/similar directly...
I'm not sure that writing a 'special process' really gives you very much. If you wrote a special process correctly, such that it is in theory compliant to OTP design principals, it could still be ineffective in practice if it blocks or busy waits in a loop somewhere, and doesn't invoke sys when it should, so you really have at most a small optimisation over using gen_server/gen_fsm with a zero timeout (or by having an async message handler which does the polling and sends a message to self to trigger the next poll).
If what ever you are doing to actively poll can block (such as a blocking socket read for example), this is really big trouble, as gen_server, gen_fsm or a special process will all be stopped from fullfilling their usual obligations (which they would usually be able to either because the callback in the case of gen_server/gen_fsm returns, or because receive is called and the sys module invoked explicitly in the case of a special process).
If what you are doing to actively poll is non blocking though, you can do it, but if you poll without any delay then it effectively becomes a busy wait (it's not quite because the loop will include a receive call somewhere, which means the process will yield, giving the scheduler voluntary opportunity to run other processes, but it's not far off, and it will still be a relative CPU hog). If you can have a 1ms delay between each poll that makes a world of difference vs polling as rapidly as you can. It's not ideal, but if you MUST, it'll work. So use a timeout (as big as you can without it becoming a problem), or have an async message handler which does the polling and sends a message to self to trigger the next poll.
I have used both the supervisor and gen_server behaviours, and I can understand the practical uses for both of them. However, I don't really understand the use of the gen_fsm and the gen_event behaviours. Can someone clarify with practical examples?
Thanks in advance
One classic example for FSM would be lock with timeout which is mentioned in manual,
Another example which I implemented in my experience would be telephone lines, because phone have states, like ringing, connected, disconnected etc and some operations are allowed and some are not allowed during this states.
An example for event is logging used in https://github.com/basho/lager
gen_fsm is a neat implementation of finite state machine, you cane do roughly the same thing that you do with a gen_server, and in addition manage easily the different states of your application (for example in a game server select a level, a table, modify player attribute, play, save, restore...).
gen-event is an easy way to dispach event, your application send all event to the gen_event knowing nothing about potential usage, and you dynamically add and delete handlers, with different behavior (log in file, in a database, display information in graphical interface...). I have used this to have a graphical view of the processes state and communication of my application, and file log for performance analysis.
Some good examples you can find them here:
"Event handlers" and "Finite State Machines"
gen_fsm:
The gen_fsm behaviour is somewhat similar to gen_server in that it is
a specialised version of it. The biggest difference is that rather
than handling calls and casts, we're handling synchronous and
asynchronous events. Much like our dog and cat examples, each state is
represented by a function. Again, we'll go through the callbacks our
modules need to implement in order to work.
gen_event:
The gen_event behaviour differs quite a bit from the gen_server and
gen_fsm behaviours in that you are never really starting a process.
The gen_event behaviour basically runs the process that accepts and
calls functions, and you only provide a module with these functions.
This is to say, you have nothing to do with regards to event
manipulation except give your callback functions in a format that
pleases the event manager. All managing is done for free; you only
provide what's specific to your application. This is not really
surprising given OTP is, again, all about separating what's generic
from specific.
When a particular message is received by my gen_event manager process, I want it to stop after all handlers have handled it and before they get and handle any other events. The only way I could find is this:
-module(manager).
...
stop(Reason) ->
gen_event:sync_notify(manager, {stop, Reason}),
gen_event:stop(manager).
But this requires all handlers to return remove_handler from handle_event({stop, Reason}, State), otherwise they could handle an event sent from a different process after sync_notify and before stop. I would prefer to have an approach that imposes no requirements on handlers.
As far as I know, there is no other way to do it than the one you're using for handling in a way that is truly limited to one call, outside of just plainly killing the event manager with exit(Pid, Reason) or ordering it to be shut down by its own supervisor.
I am creating a test app where is one supervisor with simple_one_for_one strategy and many worker children added dynamically to it. How to implement callback (or receive a message) in supervisor that will be called when child exit normally?
Main goal is to notify some other process that all supervised worker processes are done and it's time to show final report.
How to design such kind of behavior? Should I create my own behavior that combine supervisor and gen_server, or there is a way to do this with standard otp behaviors?
There are two ways to do such a notification. The first is to simply monitor the child from the beginning. By using erlang:monitor/2, a third party can whether a process is alive or not. When the monitored process dies, the result will be turned into a message that will give the reason for it to the monitoring process.
The other way could be to use a bit of message sending in the process' terminate/2 function (terminate/3 if it's a gen_fsm). This far more brittle because the terminate function will not be called in all circumstances.
The monitor option is far superior.