在持久对象内开启并发独占区:区内可等待外部输入输出,其他事件排队等候。
源码浏览已生成;不能解析的文件以纯文本展示,不表示通过类型检查。
# 持久独占接口规范 0.1.0
本包让应用在当前持久对象(Durable Object)里开启一个**并发独占区**:区内应用可以等待外部输入输出(调用别的服务、读上游、跑较长的计算),而这段时间里发往该对象的其他事件(HTTP 请求、告警、套接字消息)**排队等候**,不与区内的读写交错。它对应平台的 `blockConcurrencyWhile`,典型用途是“读—改—外部调用—写”必须整体串行的请求,例如同一站点同一时刻只处理一个动态请求。
## 模型
当前编译入口仍是 `_start`,所以独占区通过**事件重入**实现(与[持久事务](../持久事务/规范.汉语.md)对称):应用在持久对象事件里调用 `执行持久独占 操作名 参数`,宿主暂停向该对象投递其他事件,重新进入应用,事件种类为 `durable-block`(应用据[网页入站接口](../网页入站/规范.汉语.md)的 `读取入站事件种类` 辨别);独占区处理入口用 `读取持久独占名`、`读取持久独占参数` 取得本次操作名和参数,做完工作后调用 `完成持久独占 结果` 设置结果;宿主待处理入口结束后恢复投递,并把结果作为 `执行持久独占` 的返回值。此重入方式是适配实现,后续可以换成直接调用类型化回调,应用所见的语义不变。
## 语义
操作名是 1 至 128 字节的文字,由应用约定,用来在独占区处理入口里选择要做的事;参数与结果都是有效 JSON 文字,各不超过 8 MiB,由宿主验证(非法 JSON 使调用失败)。独占区处理入口**看不到外层的 HTTP 请求**(`durable-block` 不是 HTTP 事件,不能读请求或设响应),外层需要交给它的请求资料(方法、路径、正文、标头等)应放进参数 JSON,结果再由外层据以构造响应。`完成持久独占` 每个独占区必须且只能成功调用一次。
区内应用可以读写持久仓(包括[持久事务](../持久事务/规范.汉语.md)的直接访问函数)、启动事务、读写[持久告警](../持久告警/规范.汉语.md)、等待任意外部输入输出;不能再开启独占区(`独占区内不可再启动独占区`)。多个独占区依次执行,不会重叠;独占区进行期间到达的其他事件在区结束后才被投递。独占区期间该对象的吞吐被完全占用,因此区内的耗时越短越好。
区内失败——处理入口抛出未捕获异常、没有调用 `完成持久独占`、结果不是有效 JSON 或超过 8 MiB、超过事件时限——不会传给平台:宿主把失败作为返回值交给外层,`执行持久独占` 抛出可用「尝试运行」捕获的豫言异常,消息以 `持久独占失败:` 开头并保留原因文字;**对象不会被重置**。这是有意的设计:平台原生的 `blockConcurrencyWhile` 回调一旦抛错就会重置整个持久对象(丢弃内存状态、使正在进行的请求失败,本地 workerd 已验),而应用里的独占区失败是常见的业务情形。处理入口自己抛出而未捕获的豫言异常在宿主边界表现为 `RuntimeError: illegal cast`,宿主会在消息后附上说明;需要向外层报告具体原因时,处理入口应自己用「尝试运行」捕获,并把原因写进 `完成持久独占` 的结果。
平台在独占区回调超过 30 秒时重置对象(本地 workerd 已验:超过 30 秒后对象被重置,请求失败)。为使超时表现为可捕获的异常而不是重置,宿主把 `durable-block` 事件的默认墙钟时限设为 25 秒,可通过构建产物的 `执行配置.json` 调整但不得超过 30 秒;时限只在豫言调用宿主能力时检查,单次外部调用本身耗时过长仍可能触及平台的 30 秒线,应用应给外部调用设置更短的超时。
## 函数
`执行持久独占 操作名 参数`:返回结果 JSON 文字。`读取持久独占名`:无参,返回操作名。`读取持久独占参数`:无参,返回与调用者传入一致的参数文字。`完成持久独占 结果`:设置结果,返回有。
## 失败情形
| 情形 | 类别 |
| --- | --- |
| 操作名不是 1 至 128 字节;参数不是有效 JSON 或超过 8 MiB | 违规:`执行持久独占` 抛可捕获异常,消息 `持久独占失败:…` |
| 处理入口失败、缺结果、超时 | 抛可捕获异常,消息 `持久独占失败:…`,对象不重置 |
| `完成持久独占` 的结果不是有效 JSON、超过 8 MiB,或重复调用 | 在独占区内由 `完成持久独占` 抛可捕获异常(`持久独占结果无效:…`),处理入口可捕获后另给结果 |
| 在非持久对象事件、事务入口内、独占区内调用 `执行持久独占`;在独占区外调用 `读取持久独占名`、`读取持久独占参数`、`完成持久独占` | 违规:抛可捕获的豫言异常 |
| 交换文字超过宿主上限(16 MiB)、平台故障、独占区超过平台的 30 秒 | 平台或宿主故障:中止当前事件(超过 30 秒时对象被重置),豫言无法捕获 |
## 跨宿主一致性
任何实现须保持:区内不与其他事件交错、区内到达的事件区后才投递;区内失败以可捕获异常报告且不重置对象;不可嵌套;参数结果按 JSON 文字原样传递(结果不必与 `完成持久独占` 的文字字节相同,但 JSON 意义相等);上述限额与失败类别。
## 一致性样例
对象里键 `n` 初为 0。五个并发请求各自 `执行持久独占 "counter" 参数`,处理入口读 `n`、等待外部 30 毫秒、写回 `n+1` 并返回新值,则五个结果恰为 1 至 5 的一个排列,最终 `n` 为 5,外部等待的区间两两不重叠;同样的读—等—写若不放进独占区,五个并发请求的结果会都是 1、最终 `n` 为 1(更新丢失)。独占区进行中到达的 `durable-fetch` 请求在区结束之后才被处理。`执行持久独占 "fail" "{}"` 而处理入口未捕获异常时,抛出以 `持久独占失败:` 开头的异常,其后对象照常服务且实例不变。`执行持久独占 "" "{}"`、`执行持久独占 "x" "不是JSON"` 抛异常。区内再 `执行持久独占` 抛出 `独占区内不可再启动独占区`。
## 边界
本包不提供带优先级的队列、超时后自动放弃的独占区、跨对象的分布式锁,也不把外层 HTTP 请求带进区内。它只用于已授权的当前持久对象,对象的名称与授权由宿主和部署配置决定。独占区不改变平台对存储读写的输入门规则,只是在区内额外挡住其他事件的投递。
# 持久独占之约 0.1.0
此包使客于当前持久对象(Durable Object)中开一**并发独占之区**:区内客可候外物之出入(呼他服务、读上游、行较长之算),而其间投于此对象之他事(HTTP 请、告警、套接字之信)**皆排队以候**,不与区内之读写交错。其当平台之 `blockConcurrencyWhile`;典型之用,乃“读、改、外呼、写”须整体串行之请,如同一站同一时惟理一动态之请。
## 模
今编译入口犹为 `_start`,故独占之区借**事重入**以成(与[持久事务](../持久事务/规范.文言.md)相对):客于持久对象之事中调 `执行持久独占 操作名 参数`,宿主止投他事于此对象,复入于客,事类为 `durable-block`(客循[网页入站之约](../网页入站/规范.文言.md)之 `读取入站事件种类` 辨之);独占区之入口以 `读取持久独占名`、`读取持久独占参数` 取本次之操作名与参,事毕则调 `完成持久独占 结果` 定其果;宿主待入口终,复投他事,而以其果为 `执行持久独占` 之返。此重入乃适配之术,他日可换类型化回调,客所见之义不易。
## 义
操作名为一至一百二十八字节之文,由客所约,以于独占区入口中择所为之事;参与果皆为有效 JSON 文,各不逾八 MiB,宿主验之(JSON 非法则调用败)。独占区之入口**不见外层之 HTTP 请**(`durable-block` 非 HTTP 之事,不得读请或设应),外层欲授之请之资(法、径、体、头等)当纳于参之 JSON,果再由外层据以造应。`完成持久独占` 每区必且惟一成功。
区内客可读写久仓(含[持久事务](../持久事务/规范.文言.md)之直读写术)、启事务、读写[持久告警](../持久告警/规范.文言.md)、候任意外物之出入;不得复开独占之区(`独占区内不可再启动独占区`)。诸区依次而行,不相叠;区行之际所至之他事,区毕乃投。区行之际此对象之吞吐尽为所占,故区内耗时愈短愈善。
区内之败——入口抛未捕之异、不曾 `完成持久独占`、果非有效 JSON 或逾八 MiB、逾事时之限——不传于平台:宿主以败为值授外层,`执行持久独占` 抛可以「尝试运行」捕之豫言异,辞以 `持久独占失败:` 起而存其因;**对象不被重置**。此乃有意之设:平台原生 `blockConcurrencyWhile` 之回调一抛错,则重置整个持久对象(弃内存之态、使方行之请败,本地 workerd 已验),而客中独占区之败乃常见之业务情形。入口自抛而未捕之豫言异,出宿主之界则显为 `RuntimeError: illegal cast`,宿主于辞后附其说;欲告外层以确因,入口当自以「尝试运行」捕之,而书其因于 `完成持久独占` 之果。
平台于独占区回调逾三十秒则重置对象(本地 workerd 已验:逾三十秒则对象被重置,请败)。欲令逾时显为可捕之异而非重置,宿主定 `durable-block` 事之默认墙钟时限为二十五秒,可由构建产物之 `执行配置.json` 调之而不得逾三十秒;时限惟于豫言呼宿主之能时察之,单次外呼自耗时过长,仍或触平台三十秒之线,客当为外呼设更短之时限。
## 术
`执行持久独占 操作名 参数`:返果 JSON 文。`读取持久独占名`:无参,返操作名。`读取持久独占参数`:无参,返与调用者所授一致之参文。`完成持久独占 结果`:定其果,返有。
## 败之情形
| 情形 | 类 |
| --- | --- |
| 操作名非一至一百二十八字节;参非有效 JSON 或逾八 MiB | 违约:`执行持久独占` 抛可捕之异,辞曰 `持久独占失败:…` |
| 入口败、无果、逾时 | 抛可捕之异,辞曰 `持久独占失败:…`,对象不重置 |
| `完成持久独占` 之果非有效 JSON、逾八 MiB 或重复调用 | 于独占区内由 `完成持久独占` 抛可捕之异(`持久独占结果无效:…`),入口捕之可另给其果 |
| 于非持久对象之事、事务入口内、独占区内调 `执行持久独占`;于独占区外调 `读取持久独占名`、`读取持久独占参数`、`完成持久独占` | 违约:抛可捕之豫言异 |
| 所换文逾宿主之限(十六 MiB)、平台之故、独占区逾平台三十秒 | 平台或宿主之故:止当前事(逾三十秒则对象被重置),豫言不可捕 |
## 跨宿主之一致
诸实现须守:区内不与他事交错、区内所至之事区后乃投;区内之败以可捕之异告之而不重置对象;不可嵌套;参与果依 JSON 文原样而传(果不必与 `完成持久独占` 所授文字节相同,然 JSON 意义相等);上述诸限与败类。
## 一致性样例
对象中键 `n` 初为 0。五并发之请各 `执行持久独占 "counter" 参`,入口读 `n`、候外物三十毫秒、写回 `n+1` 而返新值,则五果恰为一至五之一排列,终 `n` 为 5,外候之区间两两不叠;同此读、候、写若不入独占区,五并发之请所得皆为 1、终 `n` 为 1(更新遗失)。独占区行中所至之 `durable-fetch` 请,区毕乃理。`执行持久独占 "fail" "{}"` 而入口未捕其异,则抛以 `持久独占失败:` 起之异,其后对象如常而实例不易。`执行持久独占 "" "{}"`、`执行持久独占 "x" "不是JSON"` 抛异。区内复 `执行持久独占` 抛 `独占区内不可再启动独占区`。
## 界
此包不供带优先之队、逾时自弃之独占区、跨对象之分布式锁,亦不携外层 HTTP 请入区。惟用于获授之当前持久对象,对象之名与授由宿主及部署之配置定之。独占区不易平台于存储读写之输入门规则,惟于区内更挡他事之投。