网页事件流云工适配
流。豫 以豫言书于云工宿主库之上,不增宿主 JavaScript 一字。其行[网页事件流公约](../../../豫言操作系统接口/网页事件流/规范.文言.md) 0.1.0:即提响应头、逐块书文(受背压)、察断、正终与异终。
所以行之
- 响应与背压:造
TransformStream,其可读端授Response为体,以云工设置响应句柄提之;宿主于fetch、service-fetch、durable-fetch之事用Promise.race([响应已备, 运行毕]),故响应一设,fetch即返,Wasm 续行。可写端之写器司书:writer.write(字节)待读者来取而后成,此即背压。 - 察断:造“断开候”之承诺——
scheduler.wait(二十四时, {signal: AbortSignal.any([请求信号, 我方信号])})再以Promise.allSettled裹之(永不拒)。每书与每闭,皆使操作之承诺与之Promise.race,断开候居前:请求信号一止(客断),无论书本身能成与否皆返一;操作被拒(响应体读端已取消)亦返一。入站事件流已断开读请求信号之aborted与写器之desiredSize(误则null)。流终、止或断之后,经“我方信号”撤计时而释诸柄,不留悬挂之时。 - 状与柄:每 Wasm 实例内有一登记簿(流柄、写器号、状态引用、请求信号号、断开候号、我方控制器号)。流柄为“实例标记:写器句柄号”,实例标记取
crypto.randomUUID()之首十三字,故他事(句柄号纵同)得之亦辨为无效。状态零开、一客断、二已终或止、三断而后终或止。 - 校验:状态、标头(令牌、值字节、禁名、重复、数)皆于提响应头之前由豫言校之,违则抛豫言之异;书之大小先于状态之辨;事类非 HTTP 事则抛异。止用
writer.abort(new Error(因)),终用writer.close(),皆不阻于慢读者。 - 内部诸辅助之名皆以
流内起首,免与客或他适配同名。
部署之要
一、兼容标志 `enable_request_signal`:工作者配置之 compatibility_flags 必含之。无之则请求之 AbortSignal 不止(本地 workerd 已验),断无从察,客去后书或永阻于背压。云仓之 wrangler.jsonc 须为用此包之应用加此一项。
二、全局 `scheduler.wait` 与 `AbortSignal.any`:Workers 自具;Node 宿主无全局 scheduler,以 node:timers/promises 之 scheduler 垫片经 创建云工宿主({全局}) 授之,见 一致性验证/工具.mjs 之 造全局。
三、事之限:每事之豫言实例有墙钟之限,默认三十秒;需更久之流(长联)者,于应用目录置 执行配置.json,如 {"事件时限毫秒":{"durable-fetch":900000}}(至多十五分钟)。
本地 workerd 之实测(Wrangler 4.129.0,兼容日 2026-09-10,enable_request_signal,持久对象内 durable-fetch,真实 HTTP)
- 响应头先于程序毕而至;帧序、UTF-8、六十四 KiB 之界、三千小块、八十个六十四 KiB 之块、十二并发流,皆正;线上见附加标头,
Content-Type不可覆。 - 背压宽:读者止读八百毫秒,书者已出二百六十七至三百四十八个万字节之帧(套接字与管道之缓冲约三 MB 之量),而后乃阻。
- 客中止
fetch后应用续行:书约八十五至一百三十毫秒内返一,毕 D1 结算、终、终后书返二。空闲之联不即被见:断后首、二次之书仍返零,请求信号待书败而后止,第三次书返一(本地 HTTP/1.1;见组合范例三分片与心跳三百五十四毫秒之察);故久持之流当按期书心跳。 止:HTTP/1.1 之客所读者为正终(分块之尾照发),宿主志记未捕之异;欲使客可靠知败者,当先于流中书一帧误事件。- 未终未止而程序返:客久候(二十秒不见终)。
- 事逾墙钟之限:宿主于下一调即败(约三十秒,书止),响应流仍开而无人终之;订阅同不收。见下“宿主改动之请”。
- 云端(Cloudflare 边缘)之行——空闲流之限时、断是否即告、异终于 HTTP/2 之所见——待云端验证。
宿主改动之请(致宿主壳之守者;此适配不改宿主 JS)
事毕,收尾流之写器与读取器。 今宿主于事毕(正、败、逾时)不理仍登于事句柄表之流:未终之响应流悬挂,未取之订阅泄漏(云工每实例仅六十四频道之额,泄漏可尽之,此后订新频道皆得 HTTP 500)。宜于 宿主.mjs 之 执行 中、运行毕 之前加下列收尾,并于 句柄.mjs 所返之物增 全部: () => Array.from(表.values()):
// 文言:事毕(成、败、逾时皆然),其未终之写器则终之,未退之读器则退之。
// 汉语:事件结束时收尾该事件句柄表里仍登记的流写器与读取器:正常结束则 close 写器;失败或超时则 abort 写器,使响应流以错误终止而不悬挂;读取器一律 cancel,使订阅得以回收。
const 收尾流 = 失败 => {
for (const 值 of 句柄.全部()) {
try {
if (值 instanceof 全局.WritableStreamDefaultWriter) void (失败 === undefined ? 值.close() : 值.abort(失败)).catch(() => {});
else if (值 instanceof 全局.ReadableStreamDefaultReader) void 值.cancel().catch(() => {});
} catch { /* 已释放或已终的流不再收尾。 */ }
}
};
// 在 `运行().then(() => {` 之首调 收尾流();
// 在 `.catch(错 => {` 之首调 收尾流(错);
已于私有 dist 副本验之(Node 与本地 workerd 二处):补丁既施,未终之流于程序返时正终,事逾时(压 durable-fetch 之限至三百毫秒)则以“豫言执行超过时限”终而不悬挂,遗订被收;本地 workerd(真持久对象)中:未终之流于程序返时以正终收场,长流于三十秒之限而止,不复悬挂,遗订之数归零;一致性验证三组测试于补丁宿主上尽通过(二则“已知限制(待宿主改进)”之测由待办转通过)。WritableStreamDefaultWriter 与 ReadableStreamDefaultReader 于 workerd 与 Node 皆为全局之类,instanceof 可用。
一致性验证
一致性验证/ 含试验应用 事件流一致性应用(实 Wasm)与 Node 测试 事件流一致性.test.mjs(响应头先至、帧序、六十四 KiB 之界与大量小块、背压、读端取消与请求信号中止二种断、断后收尾、止、终后之义、无效与他事之流柄、非 HTTP 事、并发流、durable-fetch、附加标头诸校验之支),并有于真实 workerd 复验之驱动 事件流云端复验.test.mjs。复行之法见该目录之说明。