Ubuntu TechHive

How fetch Connects JavaScript Runtimes to Durable Compute

How fetch Connects JavaScript Runtimes to Durable Compute

Des environnements d'exécution JavaScript au calcul portable avec état...

Comment fetch connecte les environnements d'exécution JavaScript au calcul durable

Calcul durable

JavaScript est une cible d'exécution courante ; les API de la plateforme Web fournissent une interface partagée à travers ses environnements d'exécution. fetch connecte les navigateurs et les serveurs, tandis que le même modèle Request=/=Response atteint également des acteurs nommés et avec état. Le changement important réside dans ce que l'hôte peut récupérer après la fin d'une requête — ou d'un processus entier.

Considérez un flux de travail qui récupère des données, appelle un service d'IA, attend des heures pour une approbation humaine, puis publie un résultat. Sa durée de vie dépasse celle de n'importe quelle requête HTTP ou processus serveur. Les environnements d'exécution JavaScript et les API Web fournissent un modèle de programmation familier ; la durabilité permet à ce travail de survivre à l'exécution qui l'a initié.1

Environnements d'exécution et API de la plateforme Web

Un moteur exécute du JavaScript ; un environnement d'exécution ajoute des E/S. Le noyau partagé des API Web : fetch, Request, Response, Headers, les flux, URL et Web Crypto.

Environnement Environnement typique Support API Web
Navigateur Client Noyau + DOM
Node.js Serveur / cloud VM Noyau ; adaptateurs serveur HTTP
Deno Serveur / cloud VM Noyau ; Deno.serve
Bun Serveur / cloud VM Noyau ; Bun.serve
QuickJS Moteur embarqué API Web fournies par l'hôte
workerd Cloudflare / auto-hébergé Sous-ensemble Worker ; gestionnaire fetch
celld Flotte auto-hébergée Sous-ensemble compatible Workers

Le support varie selon l'environnement/version ; le DOM, CORS, les cookies et le streaming ne sont pas uniformes. Client : fetch(request) -> Promise. Serveur : handler(Request) -> Response | Promise ; les API de démarrage diffèrent.

Cette frontière commune est là où les pièces se connectent : un appel fetch peut se situer à l'intérieur d'une étape de flux de travail durable, une Request peut être routée vers un objet nommé avec état, et un hôte peut suspendre un programme pendant que le travail externe se termine. L'interface HTTP reste familière tandis que l'hôte ajoute la persistance, la planification et la récupération — non pas parce que Fetch lui-même est durable, mais parce que la durabilité peut être construite autour de lui.

L'équipe de Deno a annoncé un an de correctifs de bugs/sécurité en octobre 2026, mettant fin au développement de son environnement d'exécution ; Deno reste open source.

Exécution durable

  • Flux de travail : persistent les résultats des étapes ; après une interruption, la relecture réutilise les étapes terminées et relance le travail inachevé. Rendez les effets externes idempotents.
  • dquickts : capture le tas JS et la pile suspendue aux points de sauvegarde ; restaure et reprend dans un autre processus en utilisant la même version du moteur. Les E/S de l'hôte sont séparées.

dquickts : sauvegarder le programme en cours, pas seulement le résultat d'une étape

L'extension QuickJS démontre une forme plus profonde d'interruption et de reprise : un hôte peut mettre en pause JavaScript même au milieu d'une boucle, sérialiser le tas de l'environnement d'exécution et la pile d'appels suspendue, et écrire cet instantané sur le disque. Les objets, les fermetures, les variables locales, les tâches de promesse en attente et la position d'instruction sauvegardée font partie de l'état d'exécution récupérable.2

Le processus hôte original peut alors se terminer. Un nouveau processus charge l'instantané dans une version compatible du moteur et reprend le programme à l'instruction sauvegardée, plutôt que de relancer le flux de travail pour reconstruire sa progression. Cela rend l'hibernation et les longues attentes possibles sans garder le processus original résident.

La connexion aux E/S du flux de travail est tout aussi importante : JS_SuspendCall() peut parquer un appel hôte, et JS_ResumeWith() peut fournir son résultat après avoir restauré l'environnement d'exécution. L'exemple du projet utilise une fonction hôte de type fetch pour illustrer cette frontière ; ce n'est pas une implémentation intégrée de l'API Fetch standard. L'hôte possède toujours les E/S externes et la gestion sécurisée des effets secondaires répétés.3

%%{init: {"themeVariables": {"fontSize": "18px"}, "flowchart": {"htmlLabels": false, "curve": "linear", "nodeSpacing": 24, "rankSpacing": 32}}}%%
flowchart TB
  subgraph WF["Flux de travail"]
    direction TB
    W1["Exécuter une étape"] --> W2[("Persister le résultat de l'étape")]
    W2 -->|"redémarrage du processus"| W3["Relecture du flux de travail
Réutiliser les résultats sauvegardés"]
end subgraph JS["dquickts"] direction TB R1["Suspendre dans une boucle"] --> R2[("Instantané tas + pile
Écrit sur disque")]
R2 -->|"nouveau processus"| R3["Restaurer + reprendre
Instruction sauvegardée"]
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 acteur nommé, monothreadé, possède un stockage SQLite/KV fortement cohérent. Cloudflare superpose le routage distribué, le stockage, les alarmes et l'hibernation WebSocket sur le modèle d'API Web de workerd. fetch est la couture HTTP, pas la durabilité elle-même ; le RPC est un autre point d'entrée. L'état persisté survit à l'éviction ; les piles d'appels JS non.

Pour les charges de travail de type flux de travail, ce sont des blocs de construction complémentaires : un objet peut posséder l'état d'un travail ou d'un agent, persister la progression et planifier une alarme pour continuer plus tard. L'hibernation WebSocket de Cloudflare peut garder les clients connectés pendant que l'objet est hors mémoire. Cela récupère un acteur à partir de l'état stocké plutôt que de restaurer sa pile en cours d'exécution comme le fait dquickts.4

%%{init: {"themeVariables": {"fontSize": "18px"}, "flowchart": {"htmlLabels": false, "curve": "linear", "nodeSpacing": 24, "rankSpacing": 32}}}%%
flowchart TB
  C["Navigateur ou serveur
fetch(request)"]
W["Worker
Request → Response"]
D["Durable Object / cell
Gestionnaire fetch nommé"]
S[("SQLite / KV privé
Survit à l'éviction")]
E["Événements de réveil
Alarme / WebSocket"]
C <-->|"Request / Response"| W W <-->|"ID d'objet + stub.fetch"| D D <-->|"lecture / écriture"| S E -.->|réveil| 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 : déploiement neutre vis-à-vis du fournisseur

celld apporte le modèle Workers/Durable Objects à votre infrastructure : V8 + SQLite par cellule + un bucket de stockage d'objets partagé ; des lacunes de compatibilité s'appliquent.

Suite au passage de l'équipe Deno chez Cloudflare, le plan annoncé est de fusionner le code et les idées d'auto-hébergement distribué de celld dans workerd — ce n'est pas une intégration terminée.

Langages qui compilent en JavaScript

Un choix de langage n'a pas besoin d'être un choix d'hébergement

ClojureScript, ReScript et TypeScript compilent en JavaScript plutôt que de nécessiter une VM de production séparée. Leur interopérabilité/liaisons exposent fetch, les flux et d'autres API hôtes : choisir un langage ne signifie pas abandonner l'écosystème d'exécution JavaScript.

Les structures de données de ClojureScript ou les types de ReScript ne changent pas la frontière Request=/=Response. Une sortie compatible peut cibler des navigateurs, des serveurs ou des hôtes durables. Il s'agit de portabilité d'interface, pas d'une garantie que chaque bundle s'exécute sans changement : le JS émis, les modules et les dépendances doivent correspondre à l'hôte. Le code uniquement DOM et les bibliothèques spécifiques à Node restent des contraintes de plateforme.

FastTwitch : cartes ClojureScript, Fetch natif

FastTwitch exprime les applications HTTP comme des cartes de requête/réponse de style Ring et des fonctions de gestionnaire et middleware ordinaires. Ses adaptateurs relient ces cartes aux objets Request=/=Response natifs ; ses clients utilisent fetch natif, les flux de corps et les options de requête. Node HTTP, Deno.serve et Bun.serve diffèrent en dessous, mais le contrat du gestionnaire côté application reste cohérent.

L'avantage pratique : réutiliser le routage, l'authentification et la logique d'application lors du changement d'environnement d'exécution au lieu de reconstruire la frontière HTTP. Les fonctionnalités spécifiques à l'environnement nécessitent toujours des adaptateurs et des tests correspondants. ReScript peut se lier aux mêmes API Web ; FastTwitch est l'exemple ClojureScript, pas une exigence pour d'autres langages.

FastTwitch Celld : des gestionnaires HTTP aux cellules nommées avec état

Considérez une application de chat : donnez à chaque salle sa propre cellule au lieu de coordonner toutes les salles à l'intérieur d'un seul processus serveur. FastTwitch Celld ajoute des déclarations de cellules ClojureScript, des points d'entrée HTTP/RPC, le stockage, les alarmes et les liaisons WebSocket. HTTP utilise toujours le modèle Fetch ; la plateforme route chaque salle vers sa cellule nommée, et le code d'application persiste l'historique des messages dans le stockage SQLite/KV de cette cellule.

Après une éviction ou un redémarrage, une nouvelle activation peut reconstruire la salle à partir de cet historique stocké. Un atom ClojureScript ordinaire n'est pas automatiquement durable ; la pile d'appels non plus. Il s'agit d'une récupération d'état de style Durable Objects, pas d'instantanés d'exécution de style dquickts. L'extension n'est pas encore prête pour la publication.

%%{init: {"themeVariables": {"fontSize": "18px"}, "flowchart": {"htmlLabels": false, "curve": "linear", "nodeSpacing": 24, "rankSpacing": 32}}}%%
flowchart TB
  H["Application ClojureScript
Gestionnaires + middleware"]
F["FastTwitch
Adaptateurs Fetch natifs"]
N["Node · Deno · Bun
Application HTTP"]
X["FastTwitch Celld
Points d'entrée de cellule"]
C["Cellule : room-42
HTTP · RPC · événements"]
S[("SQLite / KV privé
Historique des messages")]
H --> F F --> N F -->|étendre| X X --> C C <-->|"persister / restaurer"| 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

Le fil conducteur : les environnements d'exécution partagés et les API Web en font un modèle d'application commun, et non une pile réseau séparée pour chaque langage ou hôte. Les journaux de flux de travail préservent le travail terminé, les instantanés d'exécution préservent l'état d'exécution, et les objets durables préservent les données et le cycle de vie d'une unité adressable. Ce sont différentes façons de laisser les charges de travail modernes survivre au-delà d'une seule requête ou d'un seul processus.