I have recently started using
handle_continue on my
gen_servers. I am using it for returning the
init callback as soon as possible and perform initialisation task on it, also, it is the responsible of handling db storage tasks.
handle_continue necessary if you don’t have too much pressure?
Where do you use it?
If you need to perform some work post-init, it’s handy to avoid the race condition described in this issue: Add info returns to gen_server by josevalim · Pull Request #1429 · erlang/otp · GitHub.
Extremely interesting, thanks!!
From Erlang -- gen_server
handle_continue/2 is invoked immediately after the previous callback, which makes it useful for performing work after initialization or for splitting the work in a callback in multiple steps, updating the process state along the way.
If we try to break down these two use cases:
Performing working after initialization: This can be used to make sure that some post-init work is definitely completed before the
gen_server goes into any other callback.
Moving initialization work from init to handle_continue has the benefit that the supervisor or starting process gets unblocked faster.
However, there is a caveat: because the supervisor becomes free to start the next child, so there is no longer any guarantee about the order of initialization work of the current and next children (and the corresponding variations in their failure semantics). So, you have to handle that in your logic.
Splitting work in a callback in multiple steps, updating the process state along the way.
This is sometimes useful, specially if you want to re-use some continue steps from multiple callbacks.
I’m using it in a distributed 2 node system in order to wait until a socket is closed before trying to open it on the node that is taking over. However, what I really want to do is pass control of the socket to the other node. Still working on that one. It’s probably pointless as (unlike failover) I don’t have a real world use case for takeover other than proving I can.