A simple GenServer, sends http requests, gets rescheduled by Pocess.send_after(...)
@impl true
def handle_info(:fetch_data, state) do
update_data() # ok | {:error, err}
reschedule()
{:noreply, state}
end
How to properly account for an error in an http request – update_data() ? I handle it inside the function, but what about the inverval of rescheduling? Should I call reschedule() from within update_data(...) and with a smaller interval?
This thread will only go somewhere if you clarify your original post further. The question you figured you’ll shoot back at me doesn’t progress anything.
Since the GenServer state is unused and since the handle_info function does not reply any response to the calling process, the only thing you can do with errors is log them for yourself.
As for rescheduling, it does not matter if you do it in the update_data/0 function or if you do it using Process.send_after/4 in the GenServer. You can see an example of Process.send_after/4 in the GenServer docs GenServer — Elixir v1.12.3
It looks like you are doing periodic updates by having the handle_info calling reschedule (I assume it will call Process.send_after(self(), :fetch_data, @some_interval)). Now if you want to have another reschedule() call on some error condition, you may end up with more than one :fetch_data loop. It is not so bad if the update_data() call is idempotent, however, consider the case when the error condition persists for a while, you may end up with an unbounded number of loops.
If you want this sort of job scheduling semantics I would consider a dedicated job library like Oban. This splits the “runtime” execution responsibilities which are handled with internal genservers from the state of the job lifecycle itself, which is managed in a database and ensures you get the retry guarantees you want across node reboots and so forth.
The issue with answering this question is that “proper” is context dependent. Retrying a message push to a genserver that is associated with say a websocket client is significantly different than retrying a background job that represents say pushing a password reset email. You have to define the constraints that constitute “proper” for you, and then we can answer more precisely.
If you store the next delay in the GenServer state you can easily do progressive delay. If the next delay is larger enough you are still failing you can quit the GenServer. All functionalities you need is included.
I am not sure what do you mean. If you want the delay to be dependent on the pass/fail status of the current result and the last delay (progressive delay), then the last delay would need to be stored somewhere. The GenServer’s state is a natural place.