heroku.rst (5508B)
1 Deploy to Heroku 2 ================ 3 4 This guide describes how to deploy a websockets server to Heroku_. The same 5 principles should apply to other Platform as a Service providers. 6 7 .. _Heroku: https://www.heroku.com/ 8 9 .. admonition:: Heroku no longer offers a free tier. 10 :class: attention 11 12 When this tutorial was written, in September 2021, Heroku offered a free 13 tier where a websockets app could run at no cost. In November 2022, Heroku 14 removed the free tier, making it impossible to maintain this document. As a 15 consequence, it isn't updated anymore and may be removed in the future. 16 17 We're going to deploy a very simple app. The process would be identical for a 18 more realistic app. 19 20 Create repository 21 ----------------- 22 23 Deploying to Heroku requires a git repository. Let's initialize one: 24 25 .. code-block:: console 26 27 $ mkdir websockets-echo 28 $ cd websockets-echo 29 $ git init -b main 30 Initialized empty Git repository in websockets-echo/.git/ 31 $ git commit --allow-empty -m "Initial commit." 32 [main (root-commit) 1e7947d] Initial commit. 33 34 Create application 35 ------------------ 36 37 Here's the implementation of the app, an echo server. Save it in a file called 38 ``app.py``: 39 40 .. literalinclude:: ../../example/deployment/heroku/app.py 41 :language: python 42 43 Heroku expects the server to `listen on a specific port`_, which is provided 44 in the ``$PORT`` environment variable. The app reads it and passes it to 45 :func:`~websockets.server.serve`. 46 47 .. _listen on a specific port: https://devcenter.heroku.com/articles/preparing-a-codebase-for-heroku-deployment#4-listen-on-the-correct-port 48 49 Heroku sends a ``SIGTERM`` signal to all processes when `shutting down a 50 dyno`_. When the app receives this signal, it closes connections and exits 51 cleanly. 52 53 .. _shutting down a dyno: https://devcenter.heroku.com/articles/dynos#shutdown 54 55 Create a ``requirements.txt`` file containing this line to declare a dependency 56 on websockets: 57 58 .. literalinclude:: ../../example/deployment/heroku/requirements.txt 59 :language: text 60 61 Create a ``Procfile``. 62 63 .. literalinclude:: ../../example/deployment/heroku/Procfile 64 65 This tells Heroku how to run the app. 66 67 Confirm that you created the correct files and commit them to git: 68 69 .. code-block:: console 70 71 $ ls 72 Procfile app.py requirements.txt 73 $ git add . 74 $ git commit -m "Initial implementation." 75 [main 8418c62] Initial implementation. 76 3 files changed, 32 insertions(+) 77 create mode 100644 Procfile 78 create mode 100644 app.py 79 create mode 100644 requirements.txt 80 81 The app is ready. Let's deploy it! 82 83 Deploy application 84 ------------------ 85 86 Follow the instructions_ to install the Heroku CLI, if you haven't done that 87 yet. 88 89 .. _instructions: https://devcenter.heroku.com/articles/getting-started-with-python#set-up 90 91 Sign up or log in to Heroku. 92 93 Create a Heroku app — you'll have to pick a different name because I'm already 94 using ``websockets-echo``: 95 96 .. code-block:: console 97 98 $ heroku create websockets-echo 99 Creating ⬢ websockets-echo... done 100 https://websockets-echo.herokuapp.com/ | https://git.heroku.com/websockets-echo.git 101 102 .. code-block:: console 103 104 $ git push heroku 105 106 ... lots of output... 107 108 remote: -----> Launching... 109 remote: Released v1 110 remote: https://websockets-echo.herokuapp.com/ deployed to Heroku 111 remote: 112 remote: Verifying deploy... done. 113 To https://git.heroku.com/websockets-echo.git 114 * [new branch] main -> main 115 116 Validate deployment 117 ------------------- 118 119 Let's confirm that your application is running as expected. 120 121 Since it's a WebSocket server, you need a WebSocket client, such as the 122 interactive client that comes with websockets. 123 124 If you're currently building a websockets server, perhaps you're already in a 125 virtualenv where websockets is installed. If not, you can install it in a new 126 virtualenv as follows: 127 128 .. code-block:: console 129 130 $ python -m venv websockets-client 131 $ . websockets-client/bin/activate 132 $ pip install websockets 133 134 Connect the interactive client — you must replace ``websockets-echo`` with the 135 name of your Heroku app in this command: 136 137 .. code-block:: console 138 139 $ python -m websockets wss://websockets-echo.herokuapp.com/ 140 Connected to wss://websockets-echo.herokuapp.com/. 141 > 142 143 Great! Your app is running! 144 145 Once you're connected, you can send any message and the server will echo it, 146 or press Ctrl-D to terminate the connection: 147 148 .. code-block:: console 149 150 > Hello! 151 < Hello! 152 Connection closed: 1000 (OK). 153 154 You can also confirm that your application shuts down gracefully. 155 156 Connect an interactive client again — remember to replace ``websockets-echo`` 157 with your app: 158 159 .. code-block:: console 160 161 $ python -m websockets wss://websockets-echo.herokuapp.com/ 162 Connected to wss://websockets-echo.herokuapp.com/. 163 > 164 165 In another shell, restart the app — again, replace ``websockets-echo`` with your 166 app: 167 168 .. code-block:: console 169 170 $ heroku dyno:restart -a websockets-echo 171 Restarting dynos on ⬢ websockets-echo... done 172 173 Go back to the first shell. The connection is closed with code 1001 (going 174 away). 175 176 .. code-block:: console 177 178 $ python -m websockets wss://websockets-echo.herokuapp.com/ 179 Connected to wss://websockets-echo.herokuapp.com/. 180 Connection closed: 1001 (going away). 181 182 If graceful shutdown wasn't working, the server wouldn't perform a closing 183 handshake and the connection would be closed with code 1006 (abnormal closure).