Recently I had to integrate plug_heartbeat in a fresh Phoenix project and I apparently have severe brain farts because I cannot figure it out.
I want my heartbeat check be at /internal/heartbeat, NOT /heartbeat (hitting that endpoint actually works), so I tried this:
pipeline :api do
plug :accepts, ["json"]
use Plug.Builder
Plug.Builder.plug(PlugHeartbeat, json: true)
end
scope "/internal" do
pipe_through :api
forward("/heartbeat", PlugHeartbeat)
end
Adding MyAppWeb to the scope statement changed nothing (actually made it worse because it said that it cannot find MyAppWeb.PlugHeartbeat which is rather bizarre).
Then I tried hitting /internal/heartbeat and get met with:
** (Plug.Conn.NotSentError) a response was neither set nor sent from the connection
No worries, it’s a really odd one: most plugs go into router.ex as you were trying … but ‘speshul’ ones go into Endpoint instead, run early and always, such as the Static plugs and body parsers. I’m still building my own ‘intuition’ on what should go where, and it would probably be nice if the documentation on the plug said it should go into endpoint.ex …
Yes. Such things eventually become a turn-off when using frameworks. Complexity and gotchas are growing and people have to rely on forums and random blog posts as opposed to framework authors actively and aggressively fighting off said complexity.
I wouldn’t dare criticizing Phoenix’s creators – they did an absolutely excellent job. But one can get frustrated in some such scenarios that at least for me should be basic and non-surprising.
But then again, I blame myself for not staying on top of all that.
Totally. I expect with any even somewhat complex framework to run into learning-curve issues, but there are a few things like the endpoint/router distinction which make technical sense but leave some gray areas. Not sure there’s anything to be done about it at this point, though I’ll drop a PR on PlugHeartbeat to add a note to the docs.