From 05a6299a3d13aa2343f57772936b5d9b8e9390e9 Mon Sep 17 00:00:00 2001
From: Coby Benveniste <41164052+probably-not@users.noreply.github.com>
Date: Sun, 26 Jan 2025 13:44:08 +0200
Subject: [PATCH] Document the Long-Poll Transport Limitations (#6057)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* Add warning to Phoenix Deployment documentation for long-polling requiring node-to-node communication

* Update the caveat and requirements list

According to the suggestion by @josevalim

Co-authored-by: José Valim <jose.valim@gmail.com>

* Update the placement of the section

Move the section to below the Putting it all together section according to suggestion by @josevalim

---------

Co-authored-by: José Valim <jose.valim@gmail.com>
---
 guides/deployment/deployment.md | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/guides/deployment/deployment.md b/guides/deployment/deployment.md
index a0fce4345e..02e03f4512 100644
--- a/guides/deployment/deployment.md
+++ b/guides/deployment/deployment.md
@@ -115,6 +115,35 @@ And that's it. Next, you can use one of our official guides to deploy:
   * [to Fly.io](fly.html), a PaaS that deploys your servers close to your users with built-in distribution support
   * and [to Heroku](heroku.html), one of the most popular PaaS.
 
+## Clustering and Long-Polling Transports
+
+Phoenix supports two types of transports for its Socket implementation: WebSocket, and Long-Polling. When generating a Phoenix project, you can see the default configuration set in the generated `endpoint.ex` file:
+
+```elixir
+socket "/live", Phoenix.LiveView.Socket,
+  websocket: [connect_info: [session: @session_options]],
+  longpoll: [connect_info: [session: @session_options]]
+```
+
+This configuration tells Phoenix that both the WebSocket and the Long-Polling options are available, and based on the client's network conditions, Phoenix will first attempt to connect to the WebSocket, falling back to the Long-Poll option after the configured timeout found in the generated `app.js` file:
+
+```javascript
+let liveSocket = new LiveSocket("/live", Socket, {
+  longPollFallbackMs: 2500,
+  params: {_csrf_token: csrfToken}
+})
+```
+
+If you are running more than one machine in production, which is the recommended approach in most cases, this automatic fallback comes with an important caveat. If you want Long-Polling to work properly, your application must either:
+
+1. Utilize the Erlang VM's clustering capabilities, so the default `Phoenix.PubSub` adapter can broadcast messages across nodes
+
+2. Choose a different `Phoenix.PubSub` adapter (such as `Phoenix.PubSub.Redis`)
+
+3. Or your deployment option must implement sticky sessions - ensuring that all requests for a specific session go to the same machine
+
+The reason for this is simple. While a WebSocket is a long-lived open connection to the same machine, long-polling works by opening a request to the server, waiting for a timeout or until the open request is fulfilled, and repeating this process. In order to preserve the state of the user's connected socket and to preserve the behaviour of a socket being long-lived, the user's process is kept alive, and each long-poll request attempts to find the user's stateful process. If the stateful process is not reachable, every request will create a new process and a new state, thereby breaking the fact that the socket is long-lived and stateful.
+
 ## Community Deployment Guides
 
   * [Render](https://render.com) has first class support for Phoenix applications. There are guides for hosting Phoenix with [Mix releases](https://render.com/docs/deploy-phoenix), [Distillery](https://render.com/docs/deploy-phoenix-distillery), and as a [Distributed Elixir Cluster](https://render.com/docs/deploy-elixir-cluster).