Chat: A 6PN Example with NATS
Find this example at https://github.com/fly-apps/6pn-demo-chat/Rationale
This is the code for a very simple chat example that uses bare websockets in Node and a Browser to connect to it.
Instead of immediately broadcasting the message to all users, the server sends the message on to a NATS server, using 6PN private networking, which broadcasts the message to all interested parties.
Preparation
As this example relies on a NATS server (or cluster) to be available, it should be deployed alongside the nats-cluster
example, within the same Fly organization.
Make a note of the app-name used to deploy the NATS cluster.
Select a name for your chat app.
Initializing
Create an app on Fly with your chosen chat app name, using fly init
:
fly init YOURAPPNAME --import example-fly.toml
Deploying
To deploy this app, we have one detail we have to pass it, the name fo the NATS cluster. The Dockerfile we use takes a build argument (NATSAPP) and turns it into an environment variable for the app to pick up when it runs. So if your NATS cluster app is called myclusterapp
then running:
fly deploy --build-arg NATSAPP=myclusterapp
Note: You can make that setting permanent by adding
[build.args]
NATSAPP="myclusterapp"
to the fly.toml file.
Once deployed, open up the web page - fly open
will get you there quickly - enter a chat handle and begin chatting.
Notes
The more interesting parts of this app happen out of sight of the users. It’s worth following the path of the NATSAPP build argument to find out more.
- NATSAPP’s value is passed as a build argument to the Dockerfile at deployment time.
- Inside the Dockerfile, the build argument is converted into an Environment variable,
NATSAPPHOST
which is retained with the image’s configuration. - When the
server.js
app starts up, it picks up theNATSAPPHOST
variable:
let natsapphost=process.env.NATSAPPHOST
- It then uses that value to connect to the NATS cluster:
const nc = NATS.connect(natsapphost+".internal");
The combination of an app name and .internal
in 6PN networking resolves to the IPV6 addresses of the first instance of all instances if that app currently running. So, if we set NATSAPP to myclusterapp
then scaling and adding nodes to myclusterapp
would automatically be reflected in myclusterapp.internal
. 6PN has a number of .internal
addresses an app can query which you can read about in the 6PN documentation.
Once the chat server has connected to the NATS cluster, it subscribes to a topic msg
and any message written to msg
will be broadcast to all web socket clients that are connected. If any of those web socket clients sends a message to the chat server, then it will publish that message to the msg
topic on the NATs cluster. It doesn’t even try to echo it locally, relying on the NATS cluster to publish to subscribers.
The NATS cluster can be scaled up and down according to demand. Chat servers will always be able to locate an available node thanks to Fly 6PN networking advertising homogenous services through DNS and .internal
addresses. You can then deploy the NATS cluster and/or the chat server to any region and know that both will have predictable names; the NATS cluster through Fly’s 6PN networking, and the chat server through Fly’s AnyCast Edge network.
Discuss
You can discuss this example (and the nats-cluster example) on the dedicated Fly Community topic.