I would like to relay a bunch of changes in our database to the client. However, I don’t want to send these changes instantly. Instead I’d like to collect these events and send them in batches. If a new event arrives, I would like to debounce sending the events to the client. There’s one exception: if the debounce has lasted longer than 1 second, I’d like to flush the buffer and send things over.
Any good examples out there on how to implement using a GenServer? Thanks!
include a timer_ref as part of the state of the GenServer, initialized to nil
have a cast-able message that can be used to send new events
in that handle_cast:
collect the messages (or counts, etc.) in the state
make a call to debounce(state) which would match on the timer_ref being nil and do a Process.send_after/4 of a message to self() for 1s later, or noop if there is already a timer_ref; this gives you your one second max
when that sent later message arrives, send the batched update to the client, and re-set the timer_ref to nil
should the message batch queue grow or some other abort trigger occur, cancel the pending message using the Process.cancel_timer/2
Which means a GenServer with two elements in its: one for the batches, one for the timer_ref; a handle_cast for batching, a handle_info for the send_after message to trigger the batched send, a debounce function to call send_after, … and that’s about it?
It sounds to me like gen_statem might be a much better solution for this use case - you basically have two states - waiting and collecting. With state timeout timers, this can lead to a very clean implementation.
Thanks a lot everyone! Really appreciate all the suggestions. Going to give gen_statem a try and will post back with whatever solution I come up with next week.