{"slug": "health-checks-for-plug-and-phoenix", "title": "Health checks for Plug and Phoenix", "summary": "This article by Johanna Larsson describes a simple pattern for implementing HTTP health checks in Plug and Phoenix applications, using a custom plug that intercepts requests to a specific path (e.g., \"/health_check\") and immediately responds with a 200 status. The health check plug should be placed first in the endpoint to minimize CPU usage and avoid logging, making it ideal for frequent probes in platforms like Kubernetes or ECS. The article also offers an alternative approach using Phoenix's router with the `log: false` option to suppress logging for health check requests.", "body_md": "Health checks for Plug and Phoenix\nI want to share a simple pattern for setting up HTTP based health checks for Plug/Phoenix applications. Health checks can be used for anything from uptime measuring to readiness/liveness probes for platforms like Kubernetes och ECS. The most simple version of one accepts requests on some specific path and responds with a 200. Another consideration is that it might run very frequently (ECS by default checks around 6 times a second) so it’s also ideal to run it as light as possible, and not generate logs. Finally, personally, I prefer having it out of the way of routing and controllers because I see it as separate from the functionality of the application. Skip to the bottom for a suggestion on how to avoid logging health checks in Phoenix while still using Phoenix.Router\n.\nThis code example works even if you don’t use Phoenix since it’s just a plug.\ndefmodule HealthCheck do\nimport Plug.Conn\ndef init(opts), do: opts\ndef call(%Plug.Conn{request_path: \"/health_check\"} = conn, _opts) do\nconn\n|> send_resp(200, \"\")\n|> halt()\nend\ndef call(conn, _opts), do: conn\nend\nTo just briefly explain it, it will grab any request with the specified request_path\nand immediately respond with an empty 200. All other requests are passed through untouched.\nYou use it by adding it to the top of your plugs. Here’s an example based on the default Phoenix project, in the Endpoint.ex\nfile:\n# hello_web/Endpoint.ex\ndefmodule HelloWeb.Endpoint do\nuse Phoenix.Endpoint, otp_app: :hello\n# Put the health check here, before anything else\nplug HealthCheck\nsocket \"/socket\", HelloWeb.UserSocket,\nwebsocket: true,\nlongpoll: false\n# Serve at \"/\" the static files from \"priv/static\" directory.\n#\n# You should set gzip to true if you are running phx.digest\n# when deploying your static files in production.\nplug Plug.Static,\nat: \"/\",\nfrom: :hello,\ngzip: false,\nonly: ~w(css fonts images js favicon.ico robots.txt)\n...\nThe reason you want it first is that it short circuits any requests to the path /health_check\n, meaning no other plugs are executed. This has two primary benefits: the first one being that you avoid unnecessary CPU cycles (no router etc). And the other being that it doesn’t get logged because it runs before Plug.Logger\n.\nIf you now try going to /health_check\nyou’ll see that no request is logged and you get an empty successful response.\nSo there you are, a very simple pattern for handling health checks in Plug and Phoenix. You don’t have to limit yourself to just responding 200, you can do any checks in that function clause and return anything, so feel free to adjust and improve for your use case.\nIf you’re not like me, and you feel strongly that the health check should be in your router (and you’re using Phoenix), but you don’t want those requests to be logged, take a look at scope/2\n. It supports setting the log level for requests for a specific scope, or even turning request logging off completely for them. Here’s an example:\nscope \"/health_check\", log: false do\nforward \"/\", HealthCheck\nend\nEnjoy!\nWritten by Johanna Larsson. Thoughts on this post? Find me on Bluesky at @jola.dev. If you like my writing, consider supporting me on Github Sponsors and get a monthly newsletter with content from my blog.\nRelated posts\nHighest Random Weight in Elixir\nA description of HRW/rendezvous hashing and the HRW elixir library.\nbunnyx: a bunny.net Elixir client library\nA best-practice Elixir library for interacting with the bunny.net API\nBuilding for the joy of building\nMy path into programming and why I've been obsessed for 20 years.", "url": "https://wpnews.pro/news/health-checks-for-plug-and-phoenix", "canonical_source": "https://jola.dev/posts/health-checks-for-plug-and-phoenix", "published_at": "2019-06-01 00:00:00+00:00", "updated_at": "2026-05-23 15:52:06.770023+00:00", "lang": "en", "topics": ["developer-tools", "cloud-computing", "open-source"], "entities": ["Plug", "Phoenix", "Kubernetes", "ECS"], "alternates": {"html": "https://wpnews.pro/news/health-checks-for-plug-and-phoenix", "markdown": "https://wpnews.pro/news/health-checks-for-plug-and-phoenix.md", "text": "https://wpnews.pro/news/health-checks-for-plug-and-phoenix.txt", "jsonld": "https://wpnews.pro/news/health-checks-for-plug-and-phoenix.jsonld"}}