Building a realtime logistics service simulator with Cloudflare Workers

The Ably Integrations provide a way to trigger events and to stream data from Ably’s pub/sub channels. This tutorial will go over how to use Ably Integrations with Cloudflare workers.

Imagine a delivery driver delivering parcels around the neighborhood. Every time a parcel is delivered, we could trigger a serverless function to track and manage the time and date of delivery, to perhaps track how many more deliveries the driver has to make that day, even give the driver the location of the next delivery.

We’ll be building a postal service delivery game using React and webhooks. Players use their arrow keys to drive a delivery van around a map to each of the postboxes that appear. Webhooks will be triggered every time the player ‘delivers’ a parcel to a postbox, this will call a Cloudflare worker which will notify a separate ‘admin page’ that the delivery has been made.


screenshot of the game we will be making

Step 1 – Create your Ably app and API key

To follow this tutorial, you will need an Ably account. Sign up for a free account if you don’t already have one.

Access to the Ably global messaging platform requires an API key for authentication. API keys exist within the context of an Ably application and each application can have multiple API keys so that you can assign different capabilities and manage access to channels and queues.

You can either create a new application for this tutorial, or use an existing one.

To create a new application and generate an API key:

  1. Log in to your Ably account dashboard
  2. Click the “Create New App” button
  3. Give it a name and click “Create app”
  4. Copy your private API key and store it somewhere. You will need it for this tutorial.

To use an existing application and API key:

  1. Select an application from “Your apps” in the dashboard
  2. In the API keys tab, choose an API key to use for this tutorial. The default “Root” API key has full access to capabilities and channels.
  3. Copy the Root API key and store it somewhere. You will need it for this tutorial.

    Copy API Key screenshot

Step2 – Building the Game

To get you up and running quickly, we’ve implemented this 2D game and made it available via this tutorial’s repository. You can clone this repository and install its dependencies as per its readme.

Step 3 – Creating your function

Cloudflare workers is a Function-as-a-Service (FaaS) platform operated by Cloudflare that lets you run pieces of code when they are triggered. They’re comparable to AWS Lambda, or Azure Functions.

Cloudflare have an npm tool called Wrangler that they use to create their Workers. You can install this using:

npm install -g @cloudflare/wrangler

You can then create new Workers by using the command wrangler generate <my-worker-name>.

If you want to learn more about Wrangler and Cloudflare Workers, you can read their documentation on the Cloudflare developer site.

For this example, we’ve already done this for you and you’ll find a Worker in the ./cloudflare-worker/ directory in your cloned repository. It looks a little like this:

addEventListener('fetch', event => {
    event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
    try {
        const body = await request.text();   // Get the body from the response
        const data = JSON.parse(body);       // Parse body to JavaScript object

        if (!data) {
            return jsonResponse(null, 'Request Body cannot be empty!');
        }

        /* Ably specific code here in the sample */

        return new Response ({ text: "I'm ok!" });

    } catch (error) {
        return new Response(error, { status: 500 });
    }
}

How the game works

The game is a React app, created using Create-React-App, that uses the react-router-dom npm package for routing.

It’s made up of two top level React components, one for the game and the other for an admin dashboard.

The player uses the arrow keys on their keyboard to drive a post van around five pre-set maps. The objective of the game is to deliver a parcel to a postbox on each level. Every time a parcel is delivered, we’re publishing a message to an Ably channel and a new postbox is shown to the user.

Ably Integrations will listen for these publish events and call our Cloudflare Worker with the body of the published message. Once our Cloudflare Worker receives the message from an integration, it will publish its own message to the Ably Channel. The dashboard is subscribed to these messages and will display the number of moves it took for the player to complete each level. In a real world scenario this might be the number of deliveries left on our driver’s shift.


Webapp sequence diagram

Step 4 – Configuring the game

The first thing we need to do to be able to use the provided code is to create a key.js file in the ./src/ directory. Inside this file you’ll export your API key as a variable:

export const ABLY_API_KEY = "YOUR_API_KEY"

Add your own Ably API key in between the quotation marks!

You will also need to add the API key into the ./cloudflare-worker/index.js file. Replace the variable near the top of the file.

Step 5 – Configuring Cloudflare

Configure your Cloudflare Worker as per these instructions in the Cloudflare Docs.

During configuration of your Cloudflare worker, you’re going edit the ./cloudflare-worker/wrangler.toml file to include your Cloudflare account_id. (You might be wondering where your Cloudflare API key goes – in order to deploy a Worker using Wrangler, you’ll configure Wrangler using its config subcommand so your API keys never touch the Worker code itself.)

Once you’re done with configuration, publish your Worker using Wrangler. After publishing your Worker to your Cloudflare account, it will have a URL, you will need this to set up Ably Integrations.

Creating an Integration Rule for a Webhook

Integrations are scalable services to trigger events and stream data from Ably’s pub/sub channels. Creating an integration rule will allow your serverless functions or your own servers to be invoked following any events on Ably.

  1. Log into your app dashboard
  2. Go to your Ably Dashboard
  3. Choose the “Integrations” tab
  4. Click “New Integration Rule” button
  5. Click the “Choose” button under “rule” type


Click on the 'New Integration Rule' button


Click on the 'Choose' button under 'Event' type

Choose the “Cloudflare Workers” option:


Select the Cloudflare Workers option

Fill out the form to provide Ably with the details it needs to invoke your Cloudflare Worker.

Your webhook will now be created, and you’ll be able to continue developing the game.

Publishing to an Ably Channel when a delivery is made

Open the file ./src/feature/player/movement.js

This file contains the React code for handling player movements, but it also contains a connection to our Ably Channel, firstly, on line 18

window.Ably.connection.on(function(stateChange) {
    console.log('New connection state is ' + stateChange.current);
})

const outboundChannel = window.Ably.channels.get('cloudflareworkerdemo');

This code establishes a connection to our “cloudflareworkerdemo” channel.

When the player completes a level the handleWin function is called, and on line 64 we publish a message to our channel.

outboundChannel.publish('player', { playerSteps },
    err => {
        if (err) {
            return console.error('Failed to publish', err);
        }
        console.log('published');
    }
)

Our message contains the number of moves the player used to deliver the parcel.

Processing the message in the Worker

Ably Integrations monitor the channel and calls the Cloudflare Worker with the message contents.
We can see how this works by taking a look at the Worker file again ./cloudflare-worker/index.js

async function publishToAbly(data) {
    try {
        const URL = `https://rest.ably.io/channels/cloudflare-bot/messages?key=${key}`;

        await fetch(`${URL}`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ data });
        });

    } catch (error) {
        return error;
    }
}

The Worker is re-publishing our initial message to a channel called cloudflare-bot using the Ably REST API. We would usually recommend that you use the Client library SDKs rather than make a direct POST to the Ably Rest API, since it is more discoverable and easier to use. In this particular case however, installing the library files in the Worker would mean bundling the entire library with your Worker, which would increase the size of your script unnecessarily.

We’ll subscribe to this channel on our dashboard to receive these notifications.

Connecting the dashboard

In our game app, there’s a React Component called Scoreboard in ./src/feature/scoreboard/index.js which contains the following code on line 12

const ably = new Realtime(ABLY_API_KEY);

ably.connection.on('connected', () => {
    console.log('Successfully connected!');

    const inboundChannel = ably.channels.get('cloudflare-bot');
    inboundChannel.subscribe(message => {
        this.scoreboard.push(message.data.playerSteps);
        this.setState(this.scoreboard);
    })
})

This is similar to the code we used to originally publish the message, but this time, we’re subscribing to the channel cloudflare-bot.

When the Cloudflare Worker re-publishes our initial message onto this channel, the code in our subscription fires.

This is a stateful React component which keeps track of the moves – “playerSteps” that our players make when they finish each level.

When a message appears on the channel, we’re updating our scoreboard array (defined when the component is created), and updating the React-managed state.

As our state is modified, React will re-draw our component with the updated move counts displayed on the page.

Congratulations, you’re done!


Animated image of the browser app in action

Next Steps

1. Take a look at the Webhooks documentation for further details about what was described in this tutorial
2. Find out more about Ably Integrations
3. Learn more about Ably features by stepping through our other Ably tutorials
4. Gain a good technical overview of how the Ably realtime platform works
5. Get in touch if you need help