Codex Cloudflarensis · Volumen II · Folio I

De
Architectura

Patterns · Theoria · Systemata

Conocer las primitivas es el principio. Saber componerlas es la maestría. Este volumen recoge los patrones de composición, las leyes distribuidas que los gobiernan, y los sistemas canonical que prueban su validez.

I
Pars Prima

Patrones de Composición

Las recetas canonical para componer primitivas. Cada una nace de un problema concreto que ninguna primitiva sola resuelve bien.

PATTERN · I
— Promptuarium Subsidiarium —
Cache-Aside
CLIENT Cliens WORKER Operarius KV Cache D1 Origo 1. Try cache · 2. Miss → DB · 3. Populate
Esencia
Worker pregunta a KV primero. Miss → consulta D1 → escribe a KV con TTL.

El patrón fundamental para proteger D1 contra carga viral. Reads frecuentes con datos que cambian poco viven en KV. Cache-aside porque Worker orquesta — no es write-through.

Pro
Reads ~10ms. D1 sólo se toca en miss. Escala a millones rps.
Con
Stale data durante TTL window. Invalidación manual al escribir.
SmartLinks redirect resolver · Feature flags · Product catalog · User profile reads
PATTERN · II
— Postscriptio Differta —
Write-Behind
CLIENT Cliens DO In-Mem D1 Persistens writes acumulan flush · alarm 10s
Esencia
Writes acumulan en DO memoria, flush periódico (alarm) a D1.

El patrón canonical para counters virales. DO.increment() incrementa this.count en nanosegundos. Cada 10s, alarm dispara flush() que escribe el delta a D1. Single-writer guarantee del DO elimina race conditions.

Pro
Writes serializados sin lock. D1 ve 1 update/10s, no 10K/seg.
Con
Si DO crashea entre flushes, pierdes hasta 10s de writes (mitigable con DO storage).
Click counter · View counter · Rate limiter · Real-time dashboard metrics
PATTERN · III
— Itinerarium Saga —
Distributed Saga
STEP 1 STEP 2 STEP 3 STEP 3 ✗ ↶ COMP 2 ↶ COMP 1 forward · fail · compensate
Esencia
Workflow ejecuta steps con función de compensación por cada uno. Si step N falla, ejecuta compensaciones N-1 → 1 en reversa.

Para transacciones distribuidas (charge → ship → notify) que cruzan servicios sin 2PC. Cada step persiste resultado. Si ship() falla, ejecutas refund() (la compensación de charge()). El runtime garantiza que cada step se ejecuta exactamente una vez gracias al replay.

Pro
Atomicity sin lock distribuido. Sobrevive crashes, retoma desde último step.
Con
Eventual atomicity (no instantánea). Compensaciones deben existir y ser idempotentes.
Stripe charge + DB write + email · Order processing · Multi-step booking · LLM pipelines
PATTERN · IV
— Diffusio Multiplex —
Fan-Out
PROD Origo QUEUE Cursus C1 C2 C3
Esencia
Producer escribe N mensajes a Queue, M consumers paralelos los procesan.

Decouple compute pesado del request path. Worker recibe webhook, encola N tareas, responde 200 inmediato. Queue distribuye batches a consumers que pueden tardar minutos. Throughput escala con número de consumers.

Pro
Latency request constante aunque trabajo crezca. Retry automático. Load smoothing.
Con
Eventual processing. Idempotencia obligatoria (at-least-once). Visibility timeout tuning.
Webhook delivery · Email sending · Image processing · Bulk imports · Notification fanout
PATTERN · V
— Distinctio Vocium —
CQRS
WRITE READ DO Dominus KV Speculum D1 Annales project
Esencia
Command Query Responsibility Segregation. Writes van por un path (DO), reads por otro (KV proyección).

Las queries de lectura son distintas a las de escritura. CQRS separa: writes serializan vía DO con strong consistency. reads consultan KV/D1 read-replicas con eventual consistency. La proyección de write a read state ocurre async vía Queue/Workflow.

Pro
Reads escalan independiente. Modelos de read optimizados (denormalizados, agregados).
Con
Complejidad arquitectural alta. Sync state lag entre write y read.
High-read SaaS dashboards · E-commerce catalogs · Social feeds · Analytics-heavy products
PATTERN · VI
— Annales Aeterni —
Event Sourcing
CMD DO Custos EVT 1 EVT 2 EVT 3 EVT 4 append-only STATE replay
Esencia
Estado se deriva replicando todos los eventos pasados. La fuente de verdad son los eventos, no el estado actual.

DO recibe comando, valida, emite evento, lo append-onlyea a su SQLite. Estado actual = events.reduce(applyEvent, initialState). Replay reconstruye estado desde el log. Soporta time-travel debugging, audit log gratis, projections múltiples.

Pro
Audit log nativo. Time-travel. Múltiples projections del mismo log.
Con
Replay caro si log enorme (snapshots ayudan). Schema evolution complicado.
Banking/finance · Medical records · Game state · Document collaboration · Audit-heavy systems
PATTERN · VII
— Tabernae Singulares —
Multi-Tenant
ROUTER DO #A tenant A DO #B tenant B DO #C tenant C Aislación per-tenant idFromName(tenantId)
Esencia
Cada tenant obtiene su propia DO instance. env.TENANT.idFromName(tenantId) garantiza aislación + single-writer.

El patrón nativo de CF para multi-tenant. Tenant A nunca interfiere con Tenant B porque viven en DOs distintos. Crash de DO de A no afecta a B. Storage SQLite local per-DO = aislación de datos. Workers for Platforms va más lejos: cada tenant deploya su propio Worker bajo tu control.

Pro
Aislación absoluta. Noisy neighbor imposible. Cost-per-tenant medible.
Con
Cross-tenant queries complicadas (broadcasting). Migration de tenants pesada.
SaaS B2B · Eigenatlas cirujanos · Cosalá hotels · Cualquier vertical multi-cliente
PATTERN · VIII
— Concilium Oraculorum —
AI Orchestration
WORKER VECTOR RAG GATEWAY Cache LLM Oraculum SANDBOX Officina
Esencia
Worker orquesta: Vectorize (RAG context) + AI Gateway (LLM call con cache) + Sandbox (ejecuta código generado).

El patrón canonical para AI agents serios. Vectorize recupera contexto semántico relevante. AI Gateway cachea respuestas idénticas (40% hit ratio típico) y mide costos. Workers AI o LLM externo genera respuesta. Si la respuesta es código, Sandbox SDK lo ejecuta en aislamiento. Workflow envuelve todo si es multi-turn con state durable.

Pro
Type-safe. Observability nativa (Gateway logs). Cache reduce costos LLM ~40%.
Con
Latency cumulativa (RAG + LLM + tool calls). Cost per request alta vs llamada directa.
Chatbots con knowledge base · Code generation agents · RAG systems · LLM-driven workflows
II
Pars Secunda

Teoremas Distribuidos

Las leyes que gobiernan por qué cada primitiva existe. No las inventaron en Cloudflare — las descubrieron en los 70s-80s, y todo sistema serverless las honra.

C
— Theorema CAP —
Consistency · Availability · Partition

"En presencia de partición de red, un sistema distribuido elige entre consistencia y disponibilidad. No las tres juntas." — Eric Brewer, 2000

Cuando dos nodos pierden contacto entre sí (partición), el sistema enfrenta un dilema: aceptar writes sólo en uno de ellos (CP, sacrificando disponibilidad en el otro) o aceptar writes en ambos (AP, sacrificando consistencia momentánea). CP y AP son las únicas opciones bajo partición.

Aplicación al stack: D1 es CP (single primary, partición → writes detenidos en replica). KV es AP (cualquier PoP acepta writes, propagan eventualmente). DO es CP per-ID (single-writer global, partición → DO espera). Saber esto explica por qué KV puede mostrar valores stale 60s después de un write — es la elección consciente AP.

P
— Lex PACELC —
Refinamiento de CAP

"Si Partition (P), elige Availability (A) o Consistency (C). Else (E), elige Latency (L) o Consistency (C)." — Daniel Abadi, 2010

CAP sólo describe partición. PACELC añade: fuera de partición, sigue habiendo tradeoff entre latencia y consistencia. Para responder rápido, replicas leen sin consultar primary (consistency lag). Para consistencia fuerte, esperan al primary (latency).

Por eso D1 read replicas pueden retornar datos ~10s atrasados respecto al primary. No es bug — es la elección PACELC: prefieren latencia baja en lectura sobre frescura absoluta. KV es PA/EL (eventual + low latency). DO es PC/EC (strong + sacrifica latencia para garantizar serialización).

I
— Lex Idempotentiae —
Operación Idempotente

"Una operación es idempotente si ejecutarla N veces produce el mismo resultado que ejecutarla una vez."

Queue garantiza at-least-once delivery. Esto significa que tu consumer puede recibir el mismo mensaje 2-N veces. Si tu handler hace charge_credit_card(amount) sin idempotency key, cobrarás 2-N veces.

Solución: cada operación incluye un idempotency key único. El consumer guarda keys procesados (en KV con TTL, o D1). Si el key ya fue visto, retorna el resultado cacheado sin reejecutar. Esta ley aplica a Workflows (steps deben ser idempotentes para replay), Queues (retry), DO RPC (network reintentos). Sin idempotencia, los sistemas distribuidos corrompen estado silenciosamente.

L
— Tempus Logicum —
Lamport Timestamps

"En sistemas distribuidos, no existe un 'ahora' global. Sólo existe el orden causal entre eventos." — Leslie Lamport, 1978

Dos eventos en máquinas distintas no pueden compararse por reloj físico (clocks drift). Lamport propuso: cada nodo lleva un contador local, lo incrementa en cada evento, lo envía con cada mensaje. Recipiente toma max(local, recibido) + 1.

Resultado: orden parcial entre eventos relacionados causalmente, sin necesidad de reloj global. Implicación práctica: cuando coordinas DOs distintos, no asumas orden temporal estricto entre sus operaciones — sólo el orden establecido por mensajes explícitos. CRDTs (próximo teorema) usan vector clocks (Lamport extendido) para resolver merges.

R
— Concordia Sine Conflictu —
Conflict-free Replicated Data Types

"Estructuras de datos que pueden ser replicadas y modificadas concurrentemente sin coordinación, garantizando convergencia eventual."

Ciertas operaciones se mergean automáticamente sin conflict: increment counters, add-only sets, last-write-wins registers. Si N replicas modifican concurrent y luego sincronizan, todas convergen al mismo estado sin lock.

KV no implementa CRDTs nativamente — por eso increment falla. DO sí soporta esta lógica si tú la implementas (single-writer hace CRDT trivial). Yjs y Automerge son CRDTs populares para colaboración real-time. Si tu producto es colaborativo (docs, whiteboards), CRDT + DO + WebSockets es la receta.

B
— Lex BASE —
Basically Available, Soft state, Eventual consistency

"Alternativa a ACID para sistemas distribuidos: tolerar inconsistencia momentánea a cambio de disponibilidad."

ACID (Atomic, Consistent, Isolated, Durable) es la base de DBs tradicionales — Postgres, MySQL. BASE relaja consistency: el sistema siempre responde (BA), el state puede cambiar sin input directo (S — propagación), eventualmente todos los nodos convergen (E).

KV es BASE puro. DynamoDB también. D1 intenta ACID (vía SQLite). DO es ACID per-instance (single-writer simplifica). Saber qué primitiva opera bajo qué modelo determina cómo razonas sobre tu state. Mezclar mental models ACID con sistemas BASE es la fuente #1 de bugs distribuidos.

2
— Pactum Duarum Phasium —
Two-Phase Commit (y por qué Saga lo reemplaza)

"Atomicity distribuida vía coordinación bloqueante."

2PC fue el approach clásico: un coordinator pregunta a todos los participants "¿pueden commit?", luego envía "commit" si todos dijeron sí. Problema: si coordinator crashea entre fases, participants quedan bloqueados indefinidamente. No escala.

Saga (Pattern III) reemplaza 2PC en sistemas modernos. En vez de bloquear hasta confirmar, ejecuta steps secuenciales con compensaciones. Ofrece eventual atomicity en vez de strong atomicity. Cloudflare nunca ofreció 2PC porque no escala — Workflow es la implementación canonical de Saga en CF.

III
Pars Tertia

Sistemas de Referencia

Arquitecturas canonical que ejercitan los patrones y teoremas. Si dominas estas, dominas el stack.

I
— Forma Brevis —
SmartLinks · URL Shortener
CLIENT Cliens WORKER api-tRPC KV link cache D1 links DB DO click counter QUEUE analytics CONSUMER Worker AI WF link analyze D1 events BROWSER Render GET /r/:slug DO flush click count → Queue → Consumer → D1 events
I
Request — cliente pega /r/promo. Worker tRPC recibe.
II
Lookup — Worker pregunta KV con link:promo. Hit (99%) → resuelve. Miss → consulta D1 + populate KV con TTL 1h.
III
Geo-route — Worker lee cf.country, aplica regla de redirect específica del país, devuelve 302.
IV
Click counter — Worker llama env.COUNTER.idFromName(slug).increment(). DO acumula in-memory.
V
Async analytics — DO alarm cada 30s flush count + envía evento detallado a Queue.
VI
Consumer — Worker queue-consumer agrega events a D1 (events table). Workflow AI corre periódicamente sobre links: Browser Rendering captura preview, Workers AI analiza safety/topic, escribe metadata.
VII
Patrones aplicados — Cache-aside (II), Write-behind (IV), Fan-out (V), AI Orchestration (VI). Cuatro patrones, un sistema.
II
— Sermo Vivus —
Real-Time Chat / Collaboration
USER A USER B USER C WORKER router DO #room1 In-Mem state + SQLite DO #room2 In-Mem state + SQLite WS User A WS User B WS User C D1 history broadcast DO hibernates · WebSockets persist
I
Connect — Cada user abre WebSocket a Worker, que upgradea a DO específico (idFromName(roomId)). Patrón Multi-tenant (VII).
II
Hibernation — DO mantiene WebSockets abiertos pero libera memoria entre mensajes. Sólo paga compute por evento real, no por conexión idle.
III
Message broadcast — User A envía. DO recibe vía WebSocket. Single-writer guarantee garantiza orden serializado. DO emite a todos los WebSockets conectados.
IV
Persistence — DO también append-onlyea a su SQLite local (Event Sourcing, Pattern VI). Para history queries cross-room, replica async a D1.
V
Why DO not Pub/Sub — DO ofrece orden total dentro de un room (single-writer). Pub/Sub no garantiza orden entre subs. Para chat, orden importa.
III
— Servus Sapiens —
AI Agent · Multi-Step LLM
USER WORKER api WORKFLOW Ordo Operum VECTOR RAG GATEWAY cache LLM claude/gpt SANDBOX tool exec BROWSER scrape DO conversation D1 history Workflow orquesta steps. DO mantiene conversation context. Steps idempotentes para replay.
I
Request — User envía mensaje. Worker valida + invoca Workflow con conversationId.
II
Step 1: RAG — Workflow consulta Vectorize con embedding de la pregunta. Recupera top-K documentos relevantes.
III
Step 2: LLM — Workflow envía prompt + RAG context vía AI Gateway. Si la query exacta fue cacheada, retorna sin tocar LLM (40% hit ratio típico).
IV
Step 3: Tool calls — LLM puede pedir ejecutar código (Sandbox) o scrape web (Browser Rendering). Workflow ejecuta, alimenta resultado de vuelta al LLM.
V
Step 4: Persistence — DO guarda mensaje + respuesta en conversation state (single-writer per conversation). D1 archiva para history queries.
VI
Durability — Si Worker crashea mid-Workflow, replay desde último step exitoso. Pasos idempotentes (Idempotency theorem). Conversation state intacto en DO.
VII
Patterns aplicados — Saga (III), Multi-tenant per conversation (VII), AI Orchestration (VIII), Event Sourcing en DO (VI).
IV
Pars Quarta

Arbor Decisionis

El árbol de decisión completo. Cuando enfrentas un nuevo requirement, recorrelo de arriba a abajo.

¿Necesitas ejecutar lógica?
¿La lógica termina en segundos?
Sí, statelessWorker
Sí, pero necesita state per-entidadDurable Object
Necesita binarios pesados / GPU / Python nativoContainers
Es código no-confiable (LLM-generated, user code)Sandbox SDK
¿La lógica dura minutos/horas/días?
Sí, multi-step que debe sobrevivir crashesWorkflow
Sí, pero es solo "fire and forget" asyncQueue
¿Necesitas guardar datos?
¿Qué patrón de acceso?
Read-heavy, cambia poco, eventual OKKV (cache-aside con D1)
SQL relacional, joins, transactionsD1
Strong consistency per-entity, hot writesDurable Object
Blobs, archivos, media pesadaR2
Vectores para semantic search / RAGVectorize
Time-series events para analyticsAnalytics Engine
Cache HTTP edge clásicoCache API
DB Postgres/MySQL existenteHyperdrive (no migrar)
¿Necesitas comunicación entre componentes?
Worker → Worker, sync, mismo accountService Bindings RPC
Worker → Worker async, decoupledQueue
Real-time bidirectional con stateDO + WebSockets
Multi-step durable orchestrationWorkflow
Recibir email entranteEmail Workers
¿Necesitas inteligencia / AI?
Inferencia simple, modelos open-sourceWorkers AI
LLM externo (Claude/GPT) con cache + obsAI Gateway → LLM
Búsqueda semánticaVectorize + Workers AI embeddings
RAG completoAutoRAG ó Vectorize + Workers
Agent multi-step con toolsWorkflow + Gateway + Sandbox
¿Multi-tenancy?
Aislación absoluta per tenantDO per tenant
Tenants deployan SU código en TU plataformaWorkers for Platforms
Aislación lógica suficienteD1 con tenant_id column + RLS-style
V
Pars Quinta

Septem Peccata Capitalia

Los siete pecados arquitectónicos que cometen quienes no leyeron este codex. Evítalos.

I
— Computatio Falsa —
KV como Counter
El pecado: usar KV.get + increment + KV.put para contar. El castigo: race conditions silenciosas que pierden 30-80% bajo carga, más rate limit 1 write/sec/key. La penitencia: Durable Object con write-behind.
II
— Origo Sine Velo —
D1 Sin Cache
El pecado: dejar Worker leyendo D1 en cada request sin KV cache-aside. El castigo: primary saturado con 1K writes/sec límite, replicas stale, latencia variable. La penitencia: cache-aside disciplinado con TTL apropiado.
III
— Custos Universalis —
DO como Cache Global
El pecado: usar UN solo Durable Object como cache "global" del sistema. El castigo: single-writer guarantee se vuelve cuello de botella global, todo serializa en un isolate. La penitencia: KV para cache global, DO sólo para coordinación per-entidad.
IV
— Iteratio Sine Idempotentia —
Queue Sin Idempotencia
El pecado: consumer de Queue sin idempotency key (charge_card, send_email). El castigo: at-least-once delivery duplica operaciones, cargas dobles, emails repetidos. La penitencia: idempotency_key persistido + check antes de actuar.
V
— Replicatio Inconstans —
Workflow Steps No-Determinísticos
El pecado: usar Date.now(), Math.random(), o llamadas externas no-cacheadas dentro de un step. El castigo: replay genera valores distintos, state divergente, bugs imposibles de reproducir. La penitencia: capturar valores no-determinísticos en su propio step.
VI
— Connexio Frigida —
Postgres Sin Hyperdrive
El pecado: Worker abre nueva conexión TCP a Postgres en cada request. El castigo: handshake TLS + auth por request = 50-200ms overhead, primary se queda sin conexiones bajo carga. La penitencia: Hyperdrive — connection pool warm + query cache.
VII
— Confusio Modelorum —
Mezclar ACID y BASE
El pecado: razonar sobre KV como si fuera ACID (esperando read-after-write strong). El castigo: bugs intermitentes que aparecen sólo bajo carga global, "funciona en local". La penitencia: saber qué primitiva es ACID (D1, DO) vs BASE (KV) y diseñar acorde.
Epilogo
De Architecto Sapiente

El arquitecto novato pregunta "¿qué primitiva uso?". El arquitecto formado pregunta "¿qué tradeoff domina mi requirement?" — y la primitiva se vuelve consecuencia mecánica.

Las primitivas son notas. Los patrones son escalas. Los teoremas son armonía. Los sistemas de referencia son sinfonías ya escritas. Construir arquitectura es componer música — no copiar partituras.

El estudio nunca termina. Cada año Cloudflare añade primitivas (Containers, Sandbox, AutoRAG) y cada nueva primitiva expande el espacio de composiciones posibles. Mantén el codex vivo: revísalo trimestralmente, contrasta tus diseños contra los siete pecados, y mide tus elecciones por sus tradeoffs reales — no por su elegancia aparente.

⁘ ❦ ⁘
Volumen II compositus · Anno Domini MMXXVI · In nomine Cloudflarensis · Ad maiorem architecturae gloriam