summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/tools/third_party/websockets/docs/howto/fly.rst
blob: ed001a2aeed9f3a34236b464341071cde4b2ad4d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
Deploy to Fly
================

This guide describes how to deploy a websockets server to Fly_.

.. _Fly: https://fly.io/

.. admonition:: The free tier of Fly is sufficient for trying this guide.
    :class: tip

    The `free tier`__ include up to three small VMs. This guide uses only one.

    __ https://fly.io/docs/about/pricing/

We're going to deploy a very simple app. The process would be identical for a
more realistic app.

Create application
------------------

Here's the implementation of the app, an echo server. Save it in a file called
``app.py``:

.. literalinclude:: ../../example/deployment/fly/app.py
    :language: python

This app implements typical requirements for running on a Platform as a Service:

* it provides a health check at ``/healthz``;
* it closes connections and exits cleanly when it receives a ``SIGTERM`` signal.

Create a ``requirements.txt`` file containing this line to declare a dependency
on websockets:

.. literalinclude:: ../../example/deployment/fly/requirements.txt
    :language: text

The app is ready. Let's deploy it!

Deploy application
------------------

Follow the instructions__ to install the Fly CLI, if you haven't done that yet.

__  https://fly.io/docs/hands-on/install-flyctl/

Sign up or log in to Fly.

Launch the app — you'll have to pick a different name because I'm already using
``websockets-echo``:

.. code-block:: console

    $ fly launch
    Creating app in ...
    Scanning source code
    Detected a Python app
    Using the following build configuration:
        Builder: paketobuildpacks/builder:base
    ? App Name (leave blank to use an auto-generated name): websockets-echo
    ? Select organization: ...
    ? Select region: ...
    Created app websockets-echo in organization ...
    Wrote config file fly.toml
    ? Would you like to set up a Postgresql database now? No
    We have generated a simple Procfile for you. Modify it to fit your needs and run "fly deploy" to deploy your application.

.. admonition:: This will build the image with a generic buildpack.
    :class: tip

    Fly can `build images`__ with a Dockerfile or a buildpack. Here, ``fly
    launch`` configures a generic Paketo buildpack.

    If you'd rather package the app with a Dockerfile, check out the guide to
    :ref:`containerize an application <containerize-application>`.

    __ https://fly.io/docs/reference/builders/

Replace the auto-generated ``fly.toml`` with:

.. literalinclude:: ../../example/deployment/fly/fly.toml
    :language: toml

This configuration:

* listens on port 443, terminates TLS, and forwards to the app on port 8080;
* declares a health check at ``/healthz``;
* requests a ``SIGTERM`` for terminating the app.

Replace the auto-generated ``Procfile`` with:

.. literalinclude:: ../../example/deployment/fly/Procfile
    :language: text

This tells Fly how to run the app.

Now you can deploy it:

.. code-block:: console

    $ fly deploy

    ... lots of output...

    ==> Monitoring deployment

    1 desired, 1 placed, 1 healthy, 0 unhealthy [health checks: 1 total, 1 passing]
    --> v0 deployed successfully

Validate deployment
-------------------

Let's confirm that your application is running as expected.

Since it's a WebSocket server, you need a WebSocket client, such as the
interactive client that comes with websockets.

If you're currently building a websockets server, perhaps you're already in a
virtualenv where websockets is installed. If not, you can install it in a new
virtualenv as follows:

.. code-block:: console

    $ python -m venv websockets-client
    $ . websockets-client/bin/activate
    $ pip install websockets

Connect the interactive client — you must replace ``websockets-echo`` with the
name of your Fly app in this command:

.. code-block:: console

    $ python -m websockets wss://websockets-echo.fly.dev/
    Connected to wss://websockets-echo.fly.dev/.
    >

Great! Your app is running!

Once you're connected, you can send any message and the server will echo it,
or press Ctrl-D to terminate the connection:

.. code-block:: console

    > Hello!
    < Hello!
    Connection closed: 1000 (OK).

You can also confirm that your application shuts down gracefully.

Connect an interactive client again — remember to replace ``websockets-echo``
with your app:

.. code-block:: console

    $ python -m websockets wss://websockets-echo.fly.dev/
    Connected to wss://websockets-echo.fly.dev/.
    >

In another shell, restart the app — again, replace ``websockets-echo`` with your
app:

.. code-block:: console

    $ fly restart websockets-echo
    websockets-echo is being restarted

Go back to the first shell. The connection is closed with code 1001 (going
away).

.. code-block:: console

    $ python -m websockets wss://websockets-echo.fly.dev/
    Connected to wss://websockets-echo.fly.dev/.
    Connection closed: 1001 (going away).

If graceful shutdown wasn't working, the server wouldn't perform a closing
handshake and the connection would be closed with code 1006 (abnormal closure).