Pebellslearn by building
0%
RoadmapsMatrixCoursesSandboxSign in
Durable Objects  ›  Lesson

Coordination — A Meeting Point for Many Clients

Coordination 15 minRouting everyone who must agree to the same Durable Object lets it settle races in order and broadcast updates, for example to many WebSocket clients.

Coordination — A Meeting Point for Many Clients

Two things in Hoplink need everyone to agree. First, when two people in different cities try to claim the short code launch at the same moment, exactly one must win. Second, the owner wants a live dashboard that shows clicks the instant they happen, on every open browser tab. Both are coordination problems, and both have the same answer.

The rule

Send everyone who must agree to the same object; let it decide in order.

Because a Durable Object handles one event at a time, it can act as a referee.

Claiming a code. The race from the KV lesson — both people read null, both write — disappears when both requests go to an object that owns the claim:

export class CodeRegistry extends DurableObject {
  async claim(owner) {
    const current = await this.ctx.storage.get("owner");
    if (current) return { ok: false, owner: current };
    await this.ctx.storage.put("owner", owner);
    return { ok: true };
  }
}

// in the Worker: one registry object per code
const registry = env.REGISTRY.get(env.REGISTRY.idFromName("launch"));
const result = await registry.claim("priya");

Both requests reach the same object; the first to arrive takes the code, and the second is told who owns it. No locks, no retry loops — the order in which the object handles requests is the decision.

Live updates. A Durable Object can hold many WebSocket connections at once and push a message to all of them. Each browser tab opens a WebSocket that the Worker forwards to the link's object; when a click arrives, the object broadcasts it:

export class LinkLive extends DurableObject {
  async fetch(request) {
    const [client, server] = Object.values(new WebSocketPair());
    this.ctx.acceptWebSocket(server);            // hibernation-friendly accept
    return new Response(null, { status: 101, webSocket: client });
  }
  async recordClick(country) {
    for (const ws of this.ctx.getWebSockets()) {
      ws.send(JSON.stringify({ type: "click", country }));
    }
  }
}

Accepting with ctx.acceptWebSocket lets the object hibernate while the sockets are quiet: connections stay open, but you are not billed for an idle object sitting in memory.

The shortcut

Ask "Who needs to see the same truth at the same time?" Everyone in that group gets routed to one object named after the thing they share — the code being claimed, the link being watched, the room being joined.

Routing a live dashboardStep 1 of 4
  1. Who shares the truth?

    Every tab watching link cat must see the same stream of clicks.

Trap: sending watchers of the same link to different objects (for example, naming by visitor instead of by link). Each object then sees only part of the truth.

Drills

Answer fast — trust the rule.

quick drill

Why does routing both claims for launch to one object prevent a double claim?

quick drill

What name should the live-dashboard object use?

quick drill

What does accepting sockets with ctx.acceptWebSocket(server) allow?

quick drill

A chat feature names objects by user id, so each user in a room reaches a different object. What goes wrong?

Remember

  • Send everyone who must agree to the same object; let it decide in order.
  • Shortcut: "who needs the same truth at the same time?" — name the object after what they share.
  • Trap: naming objects by the wrong unit and splitting the truth.

Practice — level up

0/1 solved

Write your answer, then compare it with a rubric and a model answer.

ExplainWho gets the code?

Two users in different cities try to claim the short code launch at the same instant. Explain why a KV check fails here and how a Durable Object guarantees exactly one winner.