I’m exploring a complicated LiveView + Genserver design, and I could use some pointers towards ideas I don’t know about yet. I suspect I’m missing some steps or making some mistakes with the design of this.
It’s an app that tracks vehicle locations for clients. Assume we’re tracking 50-1000 vehicles at a time.
Vehicles send a location update every ~minute.
- A
Vehicle
module with a function that receives a vehicle ping, logs it to the database, then Publishes aVehicleUpdate
pubsub message with the update. - A genserver
VehicleTracker
process, one running for each vehicle in the field. This process has the current state + location of the single vehicle (in-memory cache of the database information) received via subscription from theVehicle
module. This process then runs a series of regular checks and might update its current state. E.g. if no location pings received in the last 5 minutes, mark self as “Out of contact”. This is computed state, so this an in-memory process feels like the right place for it. - A genserver
StatsTracker
process that does some aggregate statistics across a subset of vehicles (e.g. all the vehicles for CompanyA). These statistics might be things like “Number of vehicles inside the city limits of City1”. This builds a map of statistics, and when something changes it will broadcast aStatsUpdate
message with the new stats map. - A
TrackerLive
Liveview, which subscribes to both theVehicleUpdate
andStatsUpdate
messages. On mount, we fetch the intitial state from ourVehicleTracker
andStatsTracker
processes, and then after that we use the data which is pushed with every PubSub message.
My specific questions are:
- Does this structure seem ok? Anything obviously wrong?
- I chose the
VehicleTracker
andStatsTracker
because LiveViews are ephemeral, and many users might want to view these same sets of data, so calculating them in each liveview is a waste. (Also, there is long-running state like “How many vehicles have checked in in the last 5 minutes” that a long-running process can better handle). Is this best practice, to have a seperate long-lived process that liveviews consume from? - With the liveview subscribing to data updates, which of these options is best? (I suspect option 1 but welcome input)
A. Receive the message, consume the containedVehicle
data from the message.
B. Receive the message, ignore the contained data, fetch the data from the relevant Process directly (with Genserver.call).
I’m interested in specific details: how this could break LiveView diffing, how this might trigger race conditions, etc.
Thank you