Ir al contenido
RT
Volver

Durable Objects: identidad, estado y coordinación

Workers es muy bueno respondiendo HTTP.

Una app real suele necesitar algo más:

En todos esos casos aparece la misma pregunta:

¿Quién recuerda el estado de esta entidad y coordina lo que pasa con ella?

Para eso existen Durable Objects.

Qué es un Durable Object

Un Durable Object es un tipo especial de Worker que combina compute + storage.

En palabras simples:

una entidad con identidad propia, código ejecutable y estado persistente.

Déjalo en inglés: Durable Object. Después de definirlo, puedes abreviarlo como DO. “Objeto durable” suena abstracto y no ayuda en una conversación de equipo.

Modelo mental: la key es la identidad

Piensa en entidades:

room:general
cart:user_123
counter:foo
agent:thread_456

Cada key apunta a una instancia específica.

counter:foo -> DO de foo
counter:bar -> DO de bar

Eso es lo importante: identidad.

No es solo una base de datos

Una base de datos guarda datos.

Un Durable Object puede guardar datos y ejecutar lógica para una entidad concreta.

Ejemplo: una sala de chat. No solo necesitas mensajes. También puedes necesitar:

Ese tipo de coordinación es incómodo si todo son funciones stateless sueltas y una tabla genérica.

Ejemplo: counter por key

Queremos:

/increment?name=foo
/increment?name=bar

foo y bar no comparten contador.

import { DurableObject } from "cloudflare:workers";

export interface Env {
  COUNTERS: DurableObjectNamespace<Counter>;
}

export class Counter extends DurableObject<Env> {
  async getValue(): Promise<number> {
    return (await this.ctx.storage.get<number>("value")) ?? 0;
  }

  async increment(): Promise<number> {
    const current = await this.getValue();
    const next = current + 1;
    await this.ctx.storage.put("value", next);
    return next;
  }
}

export default {
  async fetch(request, env): Promise<Response> {
    const url = new URL(request.url);
    const name = url.searchParams.get("name");

    if (!name) {
      return new Response("Falta ?name=foo", { status: 400 });
    }

    const id = env.COUNTERS.idFromName(name);
    const counter = env.COUNTERS.get(id);
    const value = await counter.increment();

    return Response.json({ name, value });
  },
} satisfies ExportedHandler<Env>;

La parte clave:

const id = env.COUNTERS.idFromName(name);
const counter = env.COUNTERS.get(id);

El name decide la identidad. El binding COUNTERS es la capacidad; la key es la instancia.

Flujo de un request

Para ?name=foo:

request
  -> Worker
  -> idFromName("foo")
  -> Durable Object foo
  -> lee estado
  -> incrementa
  -> guarda
  -> responde

Otro request con foo vuelve al mismo DO. Uno con bar va a otro.

Casos donde encaja bien

CasoKey típica
Chat roomsroom:{roomId}
Carritoscart:{sessionId}
Rate limit por entidadlimit:{apiKey}
Agentes AIagent:{threadId}

En cada uno, la unidad de coordinación es obvia: la sala, la sesión, la key, el hilo.

Error común: un DO global para todo

global:app

Si todos los requests pasan por una sola entidad global, creas un cuello de botella elegante.

Durable Objects funcionan mejor cuando separas por entidad:

room:{roomId}
cart:{sessionId}
tenant:{tenantId}
agent:{threadId}

La pregunta de diseño:

¿Cuál es la unidad natural de coordinación?

Cuándo NO usaría Durable Objects

No lo usaría solo porque “necesito guardar algo”.

NecesitasMira primero
SQLD1
Object storageR2
Key-value simpleKV
Procesamiento asyncQueues

Usaría DO cuando necesitas las tres cosas juntas:

identidad + estado + coordinación

Checklist de diseño

Antes de crear un DO, responde:

  1. ¿Cuál es la entidad?
  2. ¿Cómo se construye la key?
  3. ¿Qué estado guarda?
  4. ¿Qué métodos expone?
  5. ¿Qué pasa si hay muchos objetos?
  6. ¿Qué pasa al despertar después de inactividad?
  7. ¿Qué logs necesitas por entidad?
  8. ¿Qué queda en el Worker y qué queda en el DO?

Ejemplo de diseño legible:

Entidad: sala de soporte
Key: support-room:{accountId}
Worker route: /rooms/:accountId/message
DO methods: addMessage, connectUser, getRecentMessages
Async: Queue para analytics

Ahí el sistema empieza a ser claro.

La frase para recordar

Worker = entrada HTTP
Durable Object = entidad con estado
key = identidad del objeto

Si tu problema suena a “necesito coordinar una sala, carrito, documento, tenant o agente”, Durable Objects merece estar en la conversación.


Serie Cloudflare para builders: Workers · Bindings · Durable Objects · Queues

Docs: Durable Objects · Examples · Bindings


Share this post on:

Anterior
Cómo arranco proyectos indie: Better-T-Stack y lo que elijo de adentro
Siguiente
Bindings en Cloudflare Workers: permiso + API en env