Ubuntu TechHive

How fetch Connects JavaScript Runtimes to Durable Compute

How fetch Connects JavaScript Runtimes to Durable Compute

Desde entornos de ejecución de JavaScript hasta computación portátil con estado...

Cómo fetch conecta los entornos de ejecución de JavaScript con la computación duradera

Computación duradera

JavaScript es un objetivo de ejecución común; las APIs de la plataforma web proporcionan una interfaz compartida entre sus entornos de ejecución. fetch conecta navegadores y servidores, mientras que el mismo modelo de Request=/=Response también llega a actores nombrados y con estado. El cambio importante es lo que el host puede recuperar después de que una solicitud —o un proceso completo— finaliza.

Considere un flujo de trabajo que obtiene una entrada, llama a un servicio de IA, espera horas por la aprobación humana y luego publica un resultado. Su vida útil excede cualquier solicitud HTTP o proceso de servidor individual. Los entornos de ejecución de JavaScript y las APIs web proporcionan un modelo de programación familiar; la durabilidad permite que ese trabajo sobreviva a la ejecución que lo inició.1

Entornos de ejecución y APIs de la plataforma web

Un motor ejecuta JavaScript; un entorno de ejecución añade E/S. El núcleo compartido de la API web: fetch, Request, Response, Headers, streams, URL y Web Crypto.

Entorno Entorno típico Soporte de API Web
Navegador Cliente Núcleo + DOM
Node.js Servidor / VM en la nube Núcleo; adaptadores de servidor HTTP
Deno Servidor / VM en la nube Núcleo; Deno.serve
Bun Servidor / VM en la nube Núcleo; Bun.serve
QuickJS Motor embebido APIs web suministradas por el host
workerd Cloudflare / autoalojado Subconjunto de Worker; manejador fetch
celld Flota autoalojada Subconjunto compatible con Workers

El soporte varía según el entorno/versión; DOM, CORS, cookies y streaming no son uniformes. Cliente: fetch(request) -> Promise. Servidor: handler(Request) -> Response | Promise; las APIs de inicio difieren.

Este límite común es donde las piezas se conectan: una llamada fetch puede situarse dentro de un paso de flujo de trabajo duradero, una Request puede ser enrutada a un objeto con estado nombrado, y un host puede suspender un programa mientras se completa el trabajo externo. La interfaz HTTP permanece familiar mientras el host añade persistencia, programación y recuperación —no porque Fetch en sí sea duradero, sino porque la durabilidad puede construirse a su alrededor.

El equipo de Deno anunció un año de correcciones de errores/seguridad en octubre de 2026, finalizando luego el desarrollo de su entorno de ejecución; Deno sigue siendo de código abierto.

Ejecución duradera

  • Flujos de trabajo: persisten los resultados de los pasos; tras una interrupción, la reproducción reutiliza los pasos completados y reintenta el trabajo inacabado. Haga que los efectos externos sean idempotentes.
  • dquickts: captura el heap de JS y la pila suspendida en puntos de seguridad; restaura y reanuda en otro proceso usando la misma compilación del motor. La E/S del host es independiente.

dquickts: guarde el programa en ejecución, no solo el resultado de un paso

La extensión de QuickJS demuestra una forma más profunda de interrupción y reanudación: un host puede pausar JavaScript incluso en medio de un bucle, serializar el heap del entorno de ejecución y la pila de llamadas suspendida, y escribir esa instantánea en el disco. Los objetos, cierres, variables locales, trabajos de promesas pendientes y la posición de instrucción guardada son parte del estado de ejecución recuperable.2

El proceso host original puede entonces finalizar. Un nuevo proceso carga la instantánea en una compilación de motor compatible y reanuda el programa en la instrucción guardada, en lugar de volver a ejecutar el flujo de trabajo para reconstruir su progreso. Esto hace que la hibernación y las esperas largas sean posibles sin mantener el proceso original residente.

La conexión con la E/S del flujo de trabajo es igualmente importante: JS_SuspendCall() puede aparcar una llamada del host, y JS_ResumeWith() puede suministrar su resultado después de restaurar el entorno de ejecución. El ejemplo del proyecto utiliza una función host similar a fetch para ilustrar este límite; no es una implementación integrada de la API Fetch estándar. El host sigue poseyendo la E/S externa y el manejo seguro de efectos secundarios repetidos.3

%%{init: {"themeVariables": {"fontSize": "18px"}, "flowchart": {"htmlLabels": false, "curve": "linear", "nodeSpacing": 24, "rankSpacing": 32}}}%%
flowchart TB
  subgraph WF["Flujo de trabajo"]
    direction TB
    W1["Ejecutar un paso"] --> W2[("Persistir resultado del paso")]
    W2 -->|"el proceso se reinicia"| W3["Reproducir flujo de trabajo
Reutilizar resultados guardados"]
end subgraph JS["dquickts"] direction TB R1["Suspender dentro de un bucle"] --> R2[("Instantánea de heap + pila
Escrita en disco")]
R2 -->|"nuevo proceso"| R3["Restaurar + reanudar
Instrucción guardada"]
end classDef running fill:#f8fafc,stroke:#64748b,color:#0f172a classDef saved fill:#eff6ff,stroke:#2563eb,color:#0f172a classDef resumed fill:#ecfdf5,stroke:#059669,color:#0f172a class W1,R1 running class W2,R2 saved class W3,R3 resumed style WF fill:#fff,stroke:#cbd5e1,color:#0f172a style JS fill:#fff,stroke:#cbd5e1,color:#0f172a

Durable Objects

Un actor nombrado y de un solo hilo posee almacenamiento SQLite/KV fuertemente consistente. Cloudflare añade enrutamiento distribuido, almacenamiento, alarmas e hibernación de WebSocket al modelo de API web de workerd. fetch es la costura HTTP, no la durabilidad en sí; RPC es otro punto de entrada. El estado persistido sobrevive a la expulsión; las pilas de llamadas JS no.

Para cargas de trabajo similares a flujos de trabajo, estos son bloques de construcción complementarios: un objeto puede poseer el estado de un trabajo o agente, persistir el progreso y programar una alarma para continuar más tarde. La hibernación de WebSocket de Cloudflare puede mantener a los clientes conectados mientras el objeto está fuera de la memoria. Esto recupera un actor a partir del estado almacenado en lugar de restaurar su pila en ejecución como hace dquickts.4

%%{init: {"themeVariables": {"fontSize": "18px"}, "flowchart": {"htmlLabels": false, "curve": "linear", "nodeSpacing": 24, "rankSpacing": 32}}}%%
flowchart TB
  C["Navegador o servidor
fetch(request)"]
W["Worker
Request → Response"]
D["Durable Object / cell
Manejador fetch nombrado"]
S[("SQLite / KV privado
Sobrevive a la expulsión")]
E["Eventos de activación
Alarma / WebSocket"]
C <--|"Request / Response"| W W <--|"ID de objeto + stub.fetch"| D D <--|"leer / escribir"| S E -.->|activar| D classDef handler fill:#f8fafc,stroke:#64748b,color:#0f172a classDef actor fill:#ecfdf5,stroke:#059669,color:#0f172a classDef saved fill:#eff6ff,stroke:#2563eb,color:#0f172a class C,W,E handler class D actor class S saved

celld: despliegue neutral respecto al proveedor

celld lleva el modelo de Workers/Durable Objects a su infraestructura: V8 + SQLite por celda + un bucket de almacenamiento de objetos compartido; se aplican brechas de compatibilidad.

Tras el traslado del equipo de Deno a Cloudflare, el plan anunciado es fusionar el código y las ideas de autoalojamiento distribuido de celld en workerd —no es una integración completada.

Lenguajes que compilan a JavaScript

Una elección de lenguaje no tiene por qué ser una elección de alojamiento

ClojureScript, ReScript y TypeScript compilan a JavaScript en lugar de requerir una VM de producción separada. Su interoperabilidad/bindings exponen fetch, streams y otras APIs del host: elegir un lenguaje no tiene por qué significar abandonar el ecosistema de ejecución de JavaScript.

Las estructuras de datos de ClojureScript o los tipos de ReScript no cambian el límite Request=/=Response. La salida compatible puede dirigirse a navegadores, servidores o hosts duraderos. Esto es portabilidad de interfaz, no una garantía de que cada paquete se ejecute sin cambios: el JS emitido, los módulos y las dependencias deben encajar en el host. El código exclusivo de DOM y las bibliotecas específicas de Node siguen siendo restricciones de plataforma.

FastTwitch: mapas de ClojureScript, Fetch nativo

FastTwitch expresa aplicaciones HTTP como mapas de solicitud/respuesta al estilo Ring y funciones manejadoras y middleware ordinarios. Sus adaptadores conectan esos mapas a objetos Request=/=Response nativos; sus clientes usan fetch nativo, flujos de cuerpo y opciones de solicitud. Node HTTP, Deno.serve y Bun.serve difieren por debajo, pero el contrato del manejador orientado a la aplicación se mantiene consistente.

El beneficio práctico: reutilice el enrutamiento, la autenticación y la lógica de la aplicación al cambiar de entorno de ejecución en lugar de reconstruir el límite HTTP. Las características específicas del entorno de ejecución aún requieren adaptadores y pruebas coincidentes. ReScript puede enlazarse a las mismas APIs web; FastTwitch es el ejemplo de ClojureScript, no un requisito para otros lenguajes.

FastTwitch Celld: de manejadores HTTP a celdas nombradas con estado

Considere una aplicación de chat: dé a cada sala su propia celda en lugar de coordinar todas las salas dentro de un proceso de servidor. FastTwitch Celld añade declaraciones de celdas de ClojureScript, puntos de entrada HTTP/RPC, almacenamiento, alarmas y bindings de WebSocket. HTTP sigue usando el modelo Fetch; la plataforma enruta cada sala a su celda nombrada, y el código de la aplicación persiste el historial de mensajes en el almacenamiento SQLite/KV de esa celda.

Después de una expulsión o reinicio, una nueva activación puede reconstruir la sala a partir de ese historial almacenado. Un atom ordinario de ClojureScript no es automáticamente duradero; tampoco lo es la pila de llamadas. Esto es recuperación de estado al estilo Durable Objects, no instantáneas de ejecución al estilo dquickts. La extensión aún no está lista para su lanzamiento.

%%{init: {"themeVariables": {"fontSize": "18px"}, "flowchart": {"htmlLabels": false, "curve": "linear", "nodeSpacing": 24, "rankSpacing": 32}}}%%
flowchart TB
  H["Aplicación ClojureScript
Manejadores + middleware"]
F["FastTwitch
Adaptadores Fetch nativos"]
N["Node · Deno · Bun
Aplicación HTTP"]
X["FastTwitch Celld
Puntos de entrada de celda"]
C["Celda: room-42
HTTP · RPC · eventos"]
S[("SQLite / KV privado
Historial de mensajes")]
H --> F F --> N F -->|extender| X X --> C C <--|"persistir / restaurar"| S classDef application fill:#f8fafc,stroke:#64748b,color:#0f172a classDef bridge fill:#eff6ff,stroke:#2563eb,color:#0f172a classDef durable fill:#ecfdf5,stroke:#059669,color:#0f172a class H,N application class F,X bridge class C,S durable

La línea conductora: los entornos de ejecución compartidos y las APIs web hacen de esto un modelo de aplicación común, no una pila de red separada para cada lenguaje o host. Los diarios de flujo de trabajo preservan el trabajo completado, las instantáneas del entorno de ejecución preservan el estado de ejecución, y los objetos duraderos preservan los datos y el ciclo de vida de una unidad direccionable. Estas son diferentes formas de permitir que las cargas de trabajo modernas sobrevivan más allá de una sola solicitud o proceso.