In looking do a simple, but potentially slow task after the response has been delivered to the end user, I am looking for some lifecycle hook to trigger once the response is over.
In googling this I see references to “register_before_send” – but in fact I want to execute this code after send.
I see some contradictory older threads that look somewhat complicated involving task and/or task supervisor, but it’s not clear those are relevant to the current state of phoenix.
So: what is the best practice for doing work after a response has been successfully sent?
I was imagining there would be a straightforward way to add a post-processing plug or a post-action callback.
I’m not aware of away to do this with plug, but Phoenix does emit telemetry events. You could subscribe to a telemetry [:phoenix, :endpoint, :stop] event and execute your task then.
You can decide on your own when exactly in the plug pipeline you send the response (using Plug.Conn.send_resp/1 or any code calling it). E.g. in a phoenix app that would happen as part of Phoenix.Controller.render/3. Sending a response doesn’t stop the plug pipeline though. You can have further plugs after that. You can even implement a similar callback registration to register_before_send if you want to.
If you don’t manually call Plug.Conn.send_resp will be called by plug at the end of a plug pipeline – expecting a response to be set on the conn.
Thanks for this tip; however, it appears to me that all plugs execute before the controller; so, I guess what I am going to try is having the controller call the send_resp, and then hand off to post response code.
This is a pretty typical setup for an api server with a router, in which the router opens with “pipe_through”
Right, but the response is being delivered to the client.
Update – the answer to that particular one is: I wasn’t returning the modified new conn, which probably gets marked with “response sent” for downstream record keeping.
Nonetheless, let me redirect to putting the plug in endpoint.ex instead of the pipeline, which would be the more general solution if I can make it work!