向授权队列投递单条与批量 JSON 消息,并在队列事件中读取批次、逐条确认或延后重试。
源码浏览已生成;不能解析的文件以纯文本展示,不表示通过类型检查。
# 消息队列接口规范 0.1.0
本包让应用向获授权的消息队列投递 JSON 消息,并在队列事件里读取当前批次、逐条确认或延后重试。生产者与消费者共用一个包。队列事件里,应用据[网页入站接口](../网页入站/规范.汉语.md)的 `读取入站事件种类` 返回 `queue` 选择自己的消费入口;每一批消息对应一次事件、一个新的程序实例,程序内存不跨事件保留,需要跨批次的状态应存进持久仓或关系库。
## 生产者
`发送队列消息` 的参数依次是队列绑定名、消息体 JSON 文字和延迟秒数,投递一条消息。绑定名由宿主许可(例如 `{"QUEUE":["PAGE_QUEUE"]}`)核对:**未授权或当前部署没有配置的名称是部署错误,宿主直接中止当前请求**,空名称则由本包抛出豫言异常。消息体可以是任意 JSON 值(对象、数组、字符串、数字、布尔、`null`),本包让宿主先解析再规范化:去掉冗余空白、统一转义,数字按 IEEE 754 双精度取值(与 JS 一致,绝对值超过 2^53−1 的整数会失去精度,应改用字符串)。**输入文字与规范化后的文字都不得超过 128 KB,即 128000 个 UTF-8 字节**(平台按十进制千字节计,本地 workerd 实测恰 128000 字节可投、128001 字节被拒),嵌套不得超过 24 层(数组或对象各算一层);平台文档称上限含元数据,接近上限的消息若仍被平台拒绝,按平台失败处理。消息体里不得出现不属于 JSON 的值或宿主专用记号(形如 `{"$句柄":…}`、`{"$未定义":…}`、`{"$大整数":…}`、`{"$数字":…}` 的对象,包括借 `\u0024` 之类转义拼出的键,以及 `1e999` 之类变成无穷大的数字),否则抛出异常:这些记号在宿主桥里表示宿主对象,不允许应用借消息体伪造。延迟秒数须在 0 至 43200(12 小时)之间,0 表示不延迟,负数或超限抛出异常。消息按 JSON 内容类型存入队列,消费者读到的正是同一个 JSON 值。
`批量发送队列消息` 的参数依次是队列绑定名和 JSON 数组文字,每项是 `{"body":任意 JSON 值,"delaySeconds":0 至 43200 的整数}`,`delaySeconds` 可省,项里不许有别的字段。数组有 1 至 100 项,每条 body 不超过 128000 字节,全部 body 合计不超过 256000 字节,数组文字不超过 1 MiB,嵌套限制同上。本包在豫言里**完整校验整个数组后**才调用平台,任一项不合格则一条也不投递;平台拒绝整批时是否有部分消息已入队由平台决定,应用需要幂等时自行保证。
生产者的两个函数都以异常报告失败,不返回状态:违规、超限、不是 JSON、含宿主记号、延迟越界都在调用平台之前抛出豫言异常,异常消息是固定的中文说明(例如 `消息体不是有效的 JSON 文字`、`消息体超过 128000 字节`、`延迟秒数须在 0 至 43200 之间`、`批量消息不得超过 100 条`);平台拒绝时抛出的异常消息是 `队列发送失败:` 或 `队列批量发送失败:` 加上平台报告的原文。应用可用「尝试运行」捕获这些异常。
## 消费者
消费者的三个函数只在当前事件是队列事件时可用,其他事件里调用会抛出可捕获的豫言异常 `当前事件不是队列事件`;它们只在这次事件内有效。`读取队列批次` 返回当前批次的 JSON 文字:`{"queue":"队列名","messages":[{"id":"消息标识","attempts":投递次数,"timestamp":入队时刻的Unix毫秒,"body":JSON 值},…]}`。`messages` 的顺序就是确认与重试所用的序号顺序,序号从 0 起;`attempts` 从 1 起,每次重新投递加 1;`timestamp` 是整数毫秒。`body` 必须是 JSON 值:若平台上的消息体不是(例如生产者用结构化克隆发送了 Date、Map、Set、二进制、`undefined`、BigInt、NaN 或无穷大),`读取队列批次` 抛出异常 `队列消息正文不是 JSON 值:序号 n`。嵌套超过宿主桥限制(32 层)的消息体会使宿主中止本次事件。
`确认队列消息` 显式确认第 n 条消息(从 0 起),表示这条消息已处理完毕,本次事件里不会再重试它。`重试队列消息` 请求重新投递第 n 条消息;第二个参数是延迟秒数,0 表示使用平台的默认延迟,否则须在 1 至 43200 之间。序号小于 0 或不小于本批消息数、延迟越界,都抛出可捕获的豫言异常(`队列消息序号越界`、`延迟秒数须在 0 至 43200 之间`)。对同一条消息重复确认、重试或先确认后重试,效果以平台为准,应用应避免。
事件的结果沿用平台语义:**程序正常结束、对某条消息没有显式重试的,视为成功**,不需要逐条确认;豫言异常无人捕获时,宿主不吞掉异常,本次队列处理失败,平台按队列的重试与死信配置整批重新投递(`attempts` 相应加一)。已显式确认的消息是否随整批重投由平台决定:Cloudflare 文档承诺不重投,但本地 Miniflare 模拟器实测会连同已确认者一起整批重投;应用不应依赖任何一方,消费处理必须幂等。单个事件另有宿主设定的运行时限。本包不提供整批确认或整批重试,需要时对每条消息调用一次。
## 一致性样例
| 情境 | 必须观察到 |
| --- | --- |
| 投递 `{"kind":"page","url":"/release/x","version":"v8","refresh":true}`,延迟 0 | 平台 `send` 收到同一个对象,选项恰为 `{"contentType":"json"}` |
| 延迟 30、43200 / -1、43201 | 前者选项含 `delaySeconds`;后者抛出异常且平台未被调用 |
| 消息体 `{"$句柄":"1"}`、`{"\u0024句柄":"1"}`、`1e999`、`{` | 均抛出异常,平台未被调用 |
| 消息体恰 128000 字节 / 多一字节 | 前者成功,后者抛出 `消息体超过 128000 字节` |
| 批量 1 项与 100 项 / 0 项与 101 项 | 前者成功;后者抛出异常,一条也未投递 |
| 批量项含 `contentType` 字段、缺 body、`delaySeconds` 为 1.5 | 均抛出异常,一条也未投递 |
| body 里含 `],[`、`{"body":1}`、引号与反斜线的字符串 | 每条 body 逐字节还原,不被误拆 |
| 平台拒绝,消息为 `Queue is full` | 异常消息为 `队列发送失败:Queue is full` |
| 队列事件里读取含三条消息的批次 | 顺序、`id`、`attempts`、毫秒 `timestamp` 与 `body` 与平台一致;此时没有任何消息被确认或重试 |
| 依次确认 0、延后重试 1(30 秒)、不处理 2 | 平台收到 `ack`、`retry({delaySeconds:30})`,第三条无调用 |
| 确认序号等于消息数或 -1;重试延迟 -1 或 43201 | 均抛出可捕获异常,平台未收到相应调用 |
| 队列事件里程序抛出未捕获异常 | 宿主把失败交还平台(不吞异常),平台整批重投,`attempts` 加一 |
| 普通 HTTP 请求里调用消费函数 | 抛出可捕获异常 `当前事件不是队列事件` |
## 边界
本包不提供 `ackAll`、`retryAll`、队列指标、队列与消费者的创建及配置(批大小、重试次数、死信队列属于部署)、消息去重、顺序保证或跨队列事务;只发送和接收 JSON 值,不发送文字或二进制内容类型,也不读取消息的内容类型。云工适配把生产者映射到 Queue 绑定的 `send` 与 `sendBatch`,把消费者映射到 `queue` 事件的 `MessageBatch`;其他平台可以用等价的队列实现,只要 JSON 值语义、限额和确认重试语义一致。
# 消息队列公约 0.1.0
此包使客向获授之消息队列投 JSON 之书,并于队列之事读当前之批,逐条确认或延而重试。生产与消费同在一包。队列之事,客据[网页入站公约](../网页入站/规范.文言.md)之 `读取入站事件种类` 返 `queue`,而择己之消费入口;一批之书当一事、一新程序之例,程序之内存不越事而留,欲跨批之状,当存于久仓或关系库。
## 生产
`发送队列消息` 之参依次为队列绑定名、消息体 JSON 文与延迟之秒,投一书。绑定名由宿主许可(如 `{"QUEUE":["PAGE_QUEUE"]}`)核之:**未授或当前部署未置之名,乃部署之误,宿主径止当前请**;空名则此包抛豫言异。消息体可为任一 JSON 之值(对象、数组、字符串、数、布尔、`null`),此包使宿主先析而后规范:去冗白,一其转义,数循 IEEE 754 双精度取值(与 JS 同,绝对值逾 2^53−1 之整数失其精,当改以字符串)。**入文与规范之后之文皆不逾一二八 KB,即一二八零零零 UTF-8 字节**(平台以十进千字节计,本地 workerd 实测恰一二八零零零字节可投、一二八零零一字节则拒),嵌套不逾二十四层(数组或对象各计一层);平台之文档言其限含元数据,近限之书若仍遭平台之拒,则以平台之败论。消息体中不得有非 JSON 之值或宿主专用之记(形如 `{"$句柄":…}`、`{"$未定义":…}`、`{"$大整数":…}`、`{"$数字":…}` 之对象,兼借 `\u0024` 之类转义所拼之键,及 `1e999` 之类化为无穷之数),否则抛异:此诸记于宿主桥乃表宿主之物,不许客借消息体而伪造。延迟之秒须在零至四万三千二百(十二时)之间,零谓不延,负或逾限则抛异。书以 JSON 内容之类入队,消费者所读即同一 JSON 之值。
`批量发送队列消息` 之参依次为队列绑定名与 JSON 数组文,每项为 `{"body":任一 JSON 值,"delaySeconds":零至四万三千二百之整数}`,`delaySeconds` 可省,项中不许他字段。数组一至百项,每 body 不逾一二八零零零字节,诸 body 合计不逾二五六零零零字节,数组文不逾一 MiB,嵌套之限同上。此包于豫言**尽验全数组而后**呼平台,一项不合则一书不投;平台拒整批时已否有部分入队,由平台定之,客欲幂等者自守之。
生产二术,皆以异告败,不返状态:违规、逾限、非 JSON、含宿主之记、延迟越界,皆于呼平台之前抛豫言异,异辞为定文(如 `消息体不是有效的 JSON 文字`、`消息体超过 128000 字节`、`延迟秒数须在 0 至 43200 之间`、`批量消息不得超过 100 条`);平台拒之,则异辞为 `队列发送失败:` 或 `队列批量发送失败:` 加平台所报之原辞。客可以「尝试运行」捕之。
## 消费
消费三术惟当前事为队列时可用,于他事而呼之,则抛可捕之豫言异 `当前事件不是队列事件`;其效止于此一事之内。`读取队列批次` 返当前批之 JSON 文:`{"queue":"队列名","messages":[{"id":"消息标识","attempts":投递之次,"timestamp":入队之刻(Unix 毫秒),"body":JSON 值},…]}`。`messages` 之序,即确认与重试所用之号序,号自零起;`attempts` 自一起,每重投加一;`timestamp` 为整数毫秒。`body` 必为 JSON 之值:若平台上之消息体非是(如生产者以结构化克隆发 Date、Map、Set、二进制、`undefined`、BigInt、NaN 或无穷),则 `读取队列批次` 抛异 `队列消息正文不是 JSON 值:序号 n`。嵌套逾宿主桥之限(三十二层)之消息体,使宿主止此一事。
`确认队列消息` 显确第 n 条(自零起),谓此书已处毕,此事之内不复重试之。`重试队列消息` 请重投第 n 条;次参为延迟之秒,零谓从平台之默认,否则须在一至四万三千二百之间。号小于零或不小于本批之数、延迟越界,皆抛可捕之豫言异(`队列消息序号越界`、`延迟秒数须在 0 至 43200 之间`)。同一条重复确认、重试或先确认后重试,其效以平台为准,客当避之。
事之果循平台之义:**程序正常而毕,某条未显重试者,视为成**,不必逐条确认;豫言之异无人捕,则宿主不吞其异,此次队列之处为败,平台按队列之重试与死信之配,整批重投(`attempts` 随加一)。已显确之书,是否随整批而重投,由平台定之:Cloudflare 之文档许其不重投,然本地 Miniflare 之模拟器实测,连已确者并整批重投;客不当倚任一方,消费之处必幂等。单事另有宿主所定之运行时限。此包不设整批确认或整批重试,欲之则于每条各呼一次。
## 一致之例
| 情境 | 必见 |
| --- | --- |
| 投 `{"kind":"page","url":"/release/x","version":"v8","refresh":true}`,延迟零 | 平台 `send` 收同一对象,选项恰为 `{"contentType":"json"}` |
| 延迟三十、四万三千二百/负一、四万三千二百零一 | 前者选项含 `delaySeconds`;后者抛异而平台未被呼 |
| 消息体 `{"$句柄":"1"}`、`{"\u0024句柄":"1"}`、`1e999`、`{` | 皆抛异,平台未被呼 |
| 消息体恰一二八零零零字节/多一字节 | 前者成,后者抛 `消息体超过 128000 字节` |
| 批量一项与百项/零项与百零一项 | 前者成;后者抛异,一书不投 |
| 批量项含 `contentType` 字段、缺 body、`delaySeconds` 为一点五 | 皆抛异,一书不投 |
| body 内有 `],[`、`{"body":1}`、含引号与反斜线之字符串 | 每 body 逐字节还原,不被误拆 |
| 平台拒之,辞为 `Queue is full` | 异辞为 `队列发送失败:Queue is full` |
| 队列事中读含三书之批 | 序、`id`、`attempts`、毫秒 `timestamp`、`body` 皆与平台同;其时无一书被确认或重试 |
| 依次确认零、延后三十秒重试一、二不处 | 平台收 `ack`、`retry({delaySeconds:30})`,第三条无所呼 |
| 确认号等于书数或负一;重试延迟负一或四万三千二百零一 | 皆抛可捕之异,平台未收相应之呼 |
| 队列事中程序抛未捕之异 | 宿主以败还平台(不吞其异),平台整批重投,`attempts` 加一 |
| 常 HTTP 请中呼消费之术 | 抛可捕之异 `当前事件不是队列事件` |
## 界
此包不设 `ackAll`、`retryAll`、队列之指标、队列与消费者之创设及配置(批之大小、重试之数、死信之队,属部署)、消息之去重、次序之保证或跨队列之事务;惟发与收 JSON 之值,不发文字或二进制之内容类,亦不读书之内容类。云工适配以生产映 Queue 绑定之 `send` 与 `sendBatch`,以消费映 `queue` 事之 `MessageBatch`;他平台可以等价之队列承之,惟 JSON 值之义、诸限及确认重试之义须同。