How to properly monitor when a LiveView socket disconnects?

So I have many live views and each of them need to send a message/remove something from the database when a client socket is disconnected.

I came across this github discussion from years ago: There is no unmount callback on Phoenix.LiveView · Issue #123 · phoenixframework/phoenix_live_view · GitHub

So I basically implemented that and it works all good, but I have a doubt…
What if there are thousands/millions of live views going on?

There would then be a single process storing a huuuuge map responsible to monitor all those views and I am concerned about it being a bottleneck

Would it be better to spawn dedicated monitor genservers for each view? If so, how could I do it so these monitors kill themselves when the parent live view dies? (But making sure that the “teardown”/“unmount” code is called first)

I’d probably use an ETS table instead of a Map, but that’s not the main problem with this approach.

For concreteness, let’s focus on the specific situation in your post (versus the “some logic” in the linked post): when a client socket is disconnected, a piece of data should be removed from the database.

The big question: what happens when the database disappears? Anything from hardware failures to accidental network misconfiguration could make it impossible for that cleanup to happen. If the system’s correctness depends on that cleanup, it’s a bug waiting to happen.

The OTP philosophy is “since we HAVE to write recovery code in case cleanup didn’t happen, skip the cleanup code entirely”. What should your system do if it discovers “leftover” records in the database that don’t correspond to a connected socket?

In the database row example, you might have the socket periodically “checkpoint” by updating a timestamp on the row. Disconnected sockets can then be spotted by periodically checking for “stale” rows and cleaning up.

1 Like

Well so my use case is the following:

I have an app where users can start private sessions to communicate with each other

The session should clean up once the actor who created the session disconnects.

So all the data inside the session doesn’t need to be persisted, I don’t really need a DB for this. At the end I ended up creating a DynamicSupervisor that spawns a GenServer when an actor creates a session and then this gen server will maintain the state.

The idea is that once the actor disconnects, the monitor will handle that and it will call the dynamic supervisor to terminate the gen server associated to that session

This session gen server also stores the data on a map in memory, I am pretty new to elixir and I don’t really know what benefits this “ETS” has over a map in memory in this case. Do you think I could benefit from it?

I think the idea in this case then is that the genserver itself should just monitor the socket, and then it can terminate itself when the socket goes away.

1 Like