I need to execute a task every, say, 3 days. Is GenServer a good fit for this?
It totally depends on your surrounding requirements. So the easiest answer is probably to show you :quantum, which advertises itself as cron-like scheduler. Please check if it fullfils your requirements. If not please tell us more about them.
The simplest solution is to create a module, which is basically wrapper for
receive or use GenServer and in the loop (created by you or using cast or call for GenServer callbacks) use Process.send_after/4 and specify the period of time.
This StackOverflow question should be helpful:
It has an example by Jose using GenServer and a list of other libraries.
How is it supposed to be helpful?
what requirements would make you change your advice of using quantum?
That’s 2 completely different ways. Which is better when?
I haven’t looked into quantum, so I can’t tell.
But some things you need to consider, which I do not know how or if at all they are handled by
- If the application has to restart, needs the timer be recovered to the old value or is it okay to start again with the maximum timespan?
- If the targeted
GenServercrashes, how easy is it to update the pid stored in the timer?
- If the ticking part of the system crashes, will it restart the interval or continue from where it left or do you need to reconfigure it completely?
As I said, it all depends on your requirements.
The link has an example GenServer written by Jose that runs code every 2 hours, which you can adjust to run every 3 days with just a bit of math. It also contains a list of libraries that can schedule code to run at any interval, persistence included.
As others mentioned, quantum can be a good fit. It has syntax of job scheduling the same as Cron. In order to run a task every days, you use this syntax that will run task every 3 days at midninght:
0 0 */3 * *
Why you consider them as different ways?
Basically all you need is server process - no matter whether you build it on your own or using GenServer, which relies deep down on
Ok. In what cases quantum can be better than GenServer?
Yeah, but that same question – why not GenServer?
I don’t mean to answer for anyone else you specifically directed your question to, but I use quantum and the main thing I like is that I can redeploy my system as many times as I want as long as it is not during a specific quantum scheduled job and the background job will still happen when it should. If a GenServer is waiting on a message back from a timer process, a redeploy forces that to start over (in the best case – int he worst case it is forgotten entirely).
As I already said, I have not used
:quantum, nor will I in the near future, also I have not read its documentation, I do not know anything about it except what was written in the abstract.
But to be honest,
:quantum is probably implemented as a
GenServer, simply because its the base of nearly everything…
But the biggest selling point of
:quantum versus doing it yourself:
:quantum is already there, you can use it. Using it will cost you no money. It will not cost you as much time as it would to reimplement its functionality again. It is already there for a while and development seems to be still active, so problems you wouldn’t even think of right from the beginning have been already encountered in
:quantum and got fixed.
Use the things that are already there, you will gain from it.
Quantum has already implemented reliable and robust job scheduling and execution. You can of course implement it yourself on top of GenServer but it may turn out more difficult than you think. The main advantage is that it is reliable, off-the-shelf component that you can grab and use as long as it fits your use case.
There are many posts here saying ‘use quantum because it already does what you want’, not going into much detail. @gregvaughn gives the best description, in that regard.
To go into a little more detail:
- Quantum runs its Scheduler as a separate worker process in your Supervision tree, (meaning that you can have multiple). This scheduler will be alive all the time, and do a little work every second, namely: looking if there is a registered job to perform at this time. Quantum does some extra work to ensure that jobs are preferably run at the ‘second rollover’ moment.
- Whenever a job should be run, this is executed by the Scheduler in a separate process (iirc) to ensure that a crashing job does not bring the whole scheduler down. If you want to do your own error handling, the recommended way is to simply use Task.Supervisor like you otherwise would.
- Quantum has its own syntax for specifying when jobs should run, based on Cron and similar tools, but it also allows for second-granularity, and for instance running your task at reboot.
- Quantum allows you to both specify the jobs to run in your configuration (and these obviously will still work after restarting your app), or at runtime (where they are probably lost when restarting unless you persist/reload them manually).
So that’s why you probably don’t want to reinvent all this stuff .
What does quantum have what GenServer doesn’t?
I think the questions you have have been answered really nicely in this thread. I suggest you go now write some code and compare both yourself.