How do you return PID in json format?

Hello.
I want to return PID as a response of a request.
But json format does not support PID…

protocol Jason.Encoder not implemented for #PID<0.691.0> of type PID, Jason.Encoder protocol must always be explicitly implemented. This protocol is implemented for the following type(s): Ecto.Association.NotLoaded, Ecto.Schema.Metadata, Any, Atom, BitString, Date, DateTime, Decimal, Float, Integer, Jason.Fragment, List, Map, NaiveDateTime, Time

How do you return it or convert PID to something available in json?

Why do you want to do that? PIDs are only meaningful in Erlang/Elixir programs.

1 Like

It is for my mobile application.

I want to make a process when a user launches the app. When the user do it, a process starts only for the user and exists by the user terminates the application.

I will implement the killing process function by sending PID from the mobile application, so I need to get the PID from my server when the process spawned.

Well, are there some better ways to maintain the state of processes?

Are you using Phoenix framework? Have you tried the WebSocket solution? It’s shipped with Phoenix, and it’s quite handy.

I’m going to try it!
Thanks.

The classic way of doing this is to use a Pid registry. Elixir comes with the build-in module Registry which can be used to do just this,

You register the process in the registry with a unique identifier for your user. Then it is easy to lookup and if the process is restarted (perhaps being part of the OTP supervision tree) then it can re-register itself. In case of using a pid directly you might end up with a stale pid.

3 Likes

This only works when the servers and the clients are in the same cluster, but the mobile phones should not be connected to the servers’ epmd because the mobile phones are not trusted, right?

1 Like

The phone shouldn’t be connected to epmd anyway. The phone can send an HTTP request to your Phoenix API which can then return any identifier you fancy – doesn’t have to be the PID itself. You just need a mapping between an ID of some sort (username, email, user’s database ID, whatever) and the PID itself. Registry is one way to do that but honestly, you can just as well keep an Elixir map in a file. :slight_smile:

Basically, you need a mapping between some sort of a user ID and the PID of the process responsible for the user.

1 Like

It really makes sense!
Thank you!

I’ll google the Registry.

I understand. There remains a problem though, how to detect a disconnection from a phone? Anyway, the end-of-life of a process should not be on the hand of a phone because it can disconnect at any time without telling the server anything. A heartbeat policy should be fine.

1 Like

Yes, it has to authenticate user.

I would like to authenticate users with guardian and guardiandb.
Without the authentication, they can send few requests.

Is this not a good way?

Thank you for the advice!

I am a bit rusty on OTP lately but you can just make sure the process gets automatically killed 5 minutes in the future if a certain message is not received. That message can indeed be a heartbeat which delays the future death of the process 5 minutes after it is received. You should have a happy path in your code where the app gracefully informs the Phoenix API that the user is disconnecting – and that should kill the process immediately. And let the timeout kill the process if the app doesn’t poke the API in time. Something like that.

1 Like

Looks good to me.

1 Like

For noobs like me who just want a quick way to encode their PIDs, here you go:

defimpl Jason.Encoder, for: PID do
  def encode(pid, _opts) do
    pid |> inspect() |> under_construction()
  end
end

All the points made above are relevant but there are valid use cases for something like this.

For example, maybe you have a table of “event logs”. That table has a json payload column. Maybe many of our events have a pid field because 1. we want to send messages back to the originating process and 2. in short-scale time intervals, the PID can be used to group events together for an unreliable per-live-view grouping.

That last paragraph might be a bit dense, sorry.

Anyway, I think there are valid cases for this.

1 Like

I can not edit my previous post, which was written hastily while on a train.

Here is an impl that actually works:

defimpl Jason.Encoder, for: PID do
  def encode(pid, _opts) do
    pid |> inspect() |> Jason.encode!()
  end
end