Subscribe to receive notifications of new posts:

Random Employee Chats at Cloudflare

2021-03-20

4 min read

Due to the COVID-19 pandemic, most Cloudflare offices closed in March 2020, and employees began working from home. Having online meetings presented its own challenges, but preserving the benefits of casual encounters in physical offices was something we struggled with. Those informal interactions, like teams talking next to the coffee machine, help form the social glue that holds companies together.

In an attempt to recreate that experience, David Wragg, an engineer at Cloudflare, introduced “Random Engineer Chats” (We’re calling them “Random Employee Chats” here since this can be applied to any team). The idea is that participants are randomly paired, and the pairs then schedule a 30-minute video call. There’s no fixed agenda for these conversations, but the participants might learn what is going on in other teams, gain new perspectives on their own work by discussing it, or meet new people.

The first iteration of Random Employee Chats used a shared spreadsheet to coordinate the process. People would sign up by adding themselves to the spreadsheet, and once a week, David would randomly form pairs from the list and send out emails with the results. Then, each pair would schedule a call at their convenience. This process was the minimum viable implementation of the idea, but it meant that the process relied on a single person.

Moving to Cloudflare Workers

We wanted to automate these repetitive manual tasks, and naturally, we wanted to use Cloudflare Workers to do it. This is a great example of a complete application that runs entirely in Cloudflare Workers on the edge with no backend or origin server.

The technical requirements included:

  • A user interface so people can sign up

  • Storage to keep track of the participants

  • A program that automatically pairs participants and notifies each pair

  • A program that reminds people to register for the next sessions

Workers met all of these requirements, and the resulting application runs in Cloudflare's edge network without any need to run code or store data on other platforms. The Workers script supplies the UI that returns static HTML and JavaScript assets, and for storage, Workers KV keeps track of people who signed in.

We also recently announced Workers Cron Triggers which allow us to run a Cloudflare Workers script on a defined schedule. The Workers Cron Triggers are perfect for pairing people up before the sessions and reminding users to register for the next session.

The User Interface

The User Interface

The interface is very simple. It shows the list of participants and allows users to register for the next session.

When a user clicks on the register button, it calls an API that adds a key in Workers KV:

key: register:ID
value: {"name":"Sven Sauleau","picture":"picture.jpg","email":"[email protected]"}

User information is stored in Workers KV and displayed in the interface to create the list of participants. The user information gets deleted during pairing so the list is ready for the next round of chats. We require weekly sign-ups from participants who want to participate in the chats to confirm their availability.

The code for the interface can be found here and the API is here.

Forming the pairs

A Random Employee Chat is a one-on-one conversation, so at a set time, the application puts participants into pairs. Each Monday morning at 0800 UTC, a Workers cron job runs the pairing script which is deployed using Wrangler.

Wrangler supports configuring the schedule for a job using the familiar cron notation. For instance, our wrangler.toml has:

name = "randengchat-cron-pair"
type = "webpack"
account_id = "..."
webpack_config = "webpack.config.js"
…

kv_namespaces = [...]

[triggers]
crons = ["0 8 * * 2"]

The pairing script is the most intricate part of the application, so let’s run through its code. First, we list the users that are currently registered. This is done using the list function in Workers KV extracting keys with the prefix register:.

const list = await KV_NAMESPACE.list({ prefix: "register:" });

If we don’t have an even number of participants, we remove one person from the list (David!).

Then, we create all possible pairs and attach a weight to them.

async function createWeightedPairs() {
  const pairs = [];
  for (let i = 0; i < keys.length - 1; i++) {
    for (let j = i + 1; j < keys.length; j++) {
      const weight = (await countTimesPaired(...)) * -1;
      pairs.push([i, j, weight]);
    }
  }
  return pairs;
}

For example, suppose four people have registered (Tom, Edie, Ivie and Ada), that’s 6 possible pairs (4 choose 2). We might end up with the following pairs and their associated weights:

(Tom, Edie, 1)
(Tom, Ivie, 0)
(Tom, Ada, 1)
(Edie, Ivie, 2)
(Edie, Ada, 0)
(Ivie, Ada, 2)

The weight is calculated using the number of times a pair matched in the past to avoid scheduling chats between people that already met. More sophisticated factors could be taken into account, such as the same office or timezone, when they last met, and etc.

We keep track of how many times the pair matched using a count kept in KV:

async function countTimesPaired(key) {
  const v = await DB.get(key, "json");
  if (v !== null && v.count) {
    return v.count;
  }
  return 0;
}

The people form a complete graph with people as nodes and the edges weighted by the number of times the two people connected by the edge have met.

The people form a complete graph with people as nodes and the edges weighted by the number of times the two people connected by the edge have met.

Next, we run a weighted matching algorithm, in our case the Blossom algorithm, which will find a maximum matching on the graph (a set of edges that maximize the number of pairs of people connected with each person appearing exactly once). As we use the weighted form of the Blossom algorithm we also minimize the path weights. This has the effect of finding the optimal set of pairs minimizing the number of times people have met previously.

In the case above the algorithm suggests the optimal pairs are  (Tom, Ivie) and (Edie, Ada). In this case, those pairs have never met before.

In this case, those pairs have never met before.

The pairs are recorded in Workers KV with their updated matching count to refine the weights at future sessions:

key: paired:ID
value: {"emails":["[email protected]","[email protected]", "count": 1]}

A notification is sent to each pair of users to notify them that they matched.

Once the pairing is done, all register: keys are deleted from KV.

All the pairing logic is here.

Reminders

The application sends users a reminder to sign up every week. For the reminder, we use another Workers cron job that runs every Thursday at 1300 UTC. The schedule in Wrangler is

[triggers]
crons = ["0 13 * * 5"]

This script is much simpler than the pairing script. It simply sends a message to a room in our company messaging platform that notifies all members of the channel.

All the reminder code is here.

We hope you find this code useful and that it inspires you to use Workers, Workers KV, Workers Unbound and Workers Cron Triggers to write large, real applications that run entirely without a backend server.

Cloudflare's connectivity cloud protects entire corporate networks, helps customers build Internet-scale applications efficiently, accelerates any website or Internet application, wards off DDoS attacks, keeps hackers at bay, and can help you on your journey to Zero Trust.

Visit 1.1.1.1 from any device to get started with our free app that makes your Internet faster and safer.

To learn more about our mission to help build a better Internet, start here. If you're looking for a new career direction, check out our open positions.
Cloudflare WorkersCloudflare Workers KVWrangler

Follow on X

Sven Sauleau|@svensauleau
Cloudflare|@cloudflare

Related posts