Custom presence tracking of mobile app users

Hi,

In our system there are web (browser) users and native mobile app users. Both connect to a Presence channel and are tracked fine when they join and leave the channel. We’d like to separate the online state, which is when the client is connected to the presence channel, from the reachable state, which is when a mobile client is not connected to the channel, but has a valid login session and is reachable via push notifications. That is, when the device is not being used or the app is closed. Our presence meta has to carry that state, e.g.:

{:ok, _} = Presence.track(socket, socket.assigns.current_user.id, %{
  online_at: System.os_time(:second) |> to_string(),
  agent_type: socket.assigns.session.agent_type,
  status: :online,
  client_ref: "some_ref"
})

One approach we tried to explore was to update the :online status with e.g. :reachable on an existing meta. When the client reconnects we’d have to find that meta by its client_ref and update the status back to :online. That’s where we met a number of challenges which makes us wonder whether we’re doing something wrong.

Simply put, we didn’t find a way to update an existing meta when the client disconnects, because by the time the presence_diff is intercepted, the presence state has already been updated and the meta in question has been deleted.

It only remains possible to track a new meta in place of the deleted one. This is fine, but then we have to allow two diff events broadcast, one with leaves and one with joins, referring to the same client, and that’s undesirable.

One possible solution would be to implement a custom Tracker with its handle_diff/2 which would manipulate the state before sending out a single broadcast. Yet, maybe we are missing something conceptually and the whole approach needs to be changed. How would you do this?

Presence tracks the existance of processes. For external clients that’s usually the socket process controlling the connection to the external client. Your “reachable” state doesn’t sound like it’s being represented by processes, so presence doesn’t really make sense.

Maybe you can describe more how you know if a mobile client has a valid login session and how you’d track them expiring.

Certainly. We do realize Presence is about tracking the processes, and even though it could be coerced to keep track of the clients in the way described above, it would certainly be a smell.

The main driving requirement behind this problem is the ability to place a call to a user. When the user is online, that is, has a WS connection, the flow is straightforward. When the user is not online but is reachable, that is the situation we’d like to handle. It should be different from the user being flatly offline because the call would still come through via a push notification. There are more moving parts, the system is a business app, not a messenger, but that’s the essence.

Login sessions are kept on the backend, they are differentiated by the agent type. Specifically, a mobile login session carries the PN tokens and such. The request to place a call is done through a restful endpoint, not through the WS connection. The backend can check the availability of the recipient(s) based on the Presence state or the mobile session validity and let the call through. This much could be done without keeping track of the reachable state in the Presence. Because the session validity check happens during the request anyway, it is not strictly necessary to have a very realtime expiration tracking.

Yet, there is a bit of desirable client-side logic that would benefit from tracking the reachable state in particular. Sometimes a call needs to be placed to a user who is known to exist, but does not yet have a complete account in the system, not even the login credentials (i.e. phone number), just bits of the profile. When the client UI initiates the call, it needs to be aware of whether the recipient user is already online (or reachable). If the user is not online/reachable, the system may send a one-time login link, but if the user does not have the credentials, the UI may also ask for the phone number (it is known to the calling user). That number will be used to send the PN to, and subsequently establish the call, and also will be registered as a login credential for the future.

All that could, as well, be implemented without caller being aware of the recipient’s reachable state, but that knowledge would reduce the number of interactions between the caller client and the backend, and also provide for a more user-friendly status representation on UI. Hence the question.

Those other states you mention don’t sound as volatile or real time as an online state to me. I’d probably just make presence one source for user state and handle the rest outside of presence.

Yes, that’s what we are inclined to do. Thanks for the perspective.