Cache managed depending on presence

Hello,

I am in a situation where I manage per-user data in a “cache” genserver (but it’s not just a cache, it also does some computation on the data). On the other side, the front-end SPA interacts through channels.

I would like to free the cache when users are idle/away. The Presence behaviour is great but a bit too much responsive in this case. For instance: I don’t want the cache to be thrown away when a user reloads the page (thus triggering successive presence_diff events).

My idea is anyway to rely on Presence.track: on each “leave” event, launch a countdown with :timer.sleep/1 in a separate process. If the user joins again in the meantime, clear the countdown (referenced in another registry-like genserver), but do empty the cache if the countdown expires.

Do you see any drawback to this approach? Thanks!

You don’t need to sleep or a new process. In cases like this, you should use Process.send_after / Process.cancel_timer, for example:

@inactive_time 10_000

# we've detected the user has gone away
def handle_info(..., state) end
  timer_ref = Process.send_after(self(), :inactive_shutdown, @inactive_time)
  {:noreply, %{state | inactive_timer: timer_ref}}
end

# we've detected the user has come back within @inactive_time, cancel shutdown
def handle_info(..., state) end
  Process.cancel_timer(state.inactive_timer)
  {:noreply, %{state | inactive_timer: nil}}
end

# user never came back, let's shutdown
def handle_info(:inactive_shutdown, state), do: {:stop, :normal, state}
6 Likes

Great, thanks!