diff --git a/docs/manual/federation.md b/docs/manual/federation.md index d015c9cb..640c3849 100644 --- a/docs/manual/federation.md +++ b/docs/manual/federation.md @@ -103,7 +103,9 @@ runtime). As separate packages, [@fedify/redis] provides [`RedisMessageQueue`] class, which is a Redis-backed implementation for production use, and [@fedify/postgres] provides [`PostgresMessageQueue`] class, which is a -PostgreSQL-backed implementation for production use. +PostgreSQL-backed implementation for production use, and [@fedify/amqp] provides +[`AmqpMessageQueue`] class, which is an AMQP broker-backed implementation for +production use. Further details are explained in the [*Message queue* section](./mq.md). @@ -116,6 +118,8 @@ Further details are explained in the [*Message queue* section](./mq.md). [`RedisMessageQueue`]: https://jsr.io/@fedify/redis/doc/mq/~/RedisMessageQueue [`PostgresMessageQueue`]: https://jsr.io/@fedify/postgres/doc/mq/~/PostgresMessageQueue +[@fedify/amqp]: https://github.com/dahlia/fedify-amqp +[`AmqpMessageQueue`]: https://jsr.io/@fedify/amqp/doc/mq/~/AmqpMessageQueue ### `manuallyStartQueue` diff --git a/docs/manual/mq.md b/docs/manual/mq.md index 29c08f7f..55a017e6 100644 --- a/docs/manual/mq.md +++ b/docs/manual/mq.md @@ -168,6 +168,51 @@ const federation = createFederation({ [`LISTEN`]: https://www.postgresql.org/docs/current/sql-listen.html [`NOTIFY`]: https://www.postgresql.org/docs/current/sql-notify.html +### `AmqpMessageQueue` + +> [!NOTE] +> The [`AmqpMessageQueue`] class is available in the [@fedify/amqp] package. + +> [!NOTE] +> +> Although it's theoretically possible to be used with any AMQP 0-9-1 broker, +> [`AmqpMessageQueue`] is primarily designed for and tested with [RabbitMQ]. + +[`AmqpMessageQueue`] is a message queue implementation that uses AMQP 0-9-1 +for message delivery. The best-known AMQP broker is [RabbitMQ]. It provides +scalability and high performance, making it suitable for production use across +various runtimes. It requires an AMQP broker setup and management. + +Best for +: Production use across various runtimes. + +Pros +: Persistent, reliable, scalable, supports multiple workers. + +Cons +: Requires AMQP broker setup and management. + +~~~~ typescript twoslash +import type { KvStore } from "@fedify/fedify"; +// ---cut-before--- +import { createFederation } from "@fedify/fedify"; +import { AmqpMessageQueue } from "@fedify/amqp"; +import { connect } from "amqplib"; + +const federation = createFederation({ +// ---cut-start--- + kv: null as unknown as KvStore, +// ---cut-end--- + queue: new AmqpMessageQueue(await connect("amqp://localhost")), // [!code highlight] + // ... other options +}); +~~~~ + +*[AMQP]: Advanced Message Queuing Protocol +[`AmqpMessageQueue`]: https://jsr.io/@fedify/amqp/doc/mq/~/AmqpMessageQueue +[@fedify/amqp]: https://github.com/dahlia/fedify-amqp +[RabbitMQ]: https://www.rabbitmq.com/ + Implementing a custom `MessageQueue` ------------------------------------ diff --git a/docs/package.json b/docs/package.json index 7ecbacb5..6fe7196b 100644 --- a/docs/package.json +++ b/docs/package.json @@ -1,6 +1,8 @@ { "devDependencies": { + "@braintree/sanitize-url": "^7.1.0", "@deno/kv": "^0.8.2", + "@fedify/amqp": "0.1.0-dev.8", "@fedify/fedify": "1.0.2", "@fedify/postgres": "0.1.0-dev.2", "@fedify/redis": "0.2.0-dev.10", @@ -9,9 +11,12 @@ "@logtape/logtape": "^0.5.1", "@shikijs/vitepress-twoslash": "^1.17.6", "@teidesu/deno-types": "^1.46.3", + "@types/amqplib": "^0.10.5", "@types/better-sqlite3": "^7.6.11", "@types/bun": "^1.1.9", + "amqplib": "^0.10.4", "cli-progress": "^3.12.0", + "dayjs": "^1.11.13", "hono": "^4.6.1", "ioredis": "^5.4.1", "markdown-it-abbr": "^2.0.0", diff --git a/docs/pnpm-lock.yaml b/docs/pnpm-lock.yaml index cd8ed251..5361e49c 100644 --- a/docs/pnpm-lock.yaml +++ b/docs/pnpm-lock.yaml @@ -8,9 +8,15 @@ importers: .: devDependencies: + '@braintree/sanitize-url': + specifier: ^7.1.0 + version: 7.1.0 '@deno/kv': specifier: ^0.8.2 version: 0.8.3 + '@fedify/amqp': + specifier: 0.1.0-dev.8 + version: 0.1.0-dev.8(web-streams-polyfill@3.3.3) '@fedify/fedify': specifier: 1.0.2 version: 1.0.2(web-streams-polyfill@3.3.3) @@ -35,15 +41,24 @@ importers: '@teidesu/deno-types': specifier: ^1.46.3 version: 1.46.3 + '@types/amqplib': + specifier: ^0.10.5 + version: 0.10.5 '@types/better-sqlite3': specifier: ^7.6.11 version: 7.6.11 '@types/bun': specifier: ^1.1.9 version: 1.1.10 + amqplib: + specifier: ^0.10.4 + version: 0.10.4 cli-progress: specifier: ^3.12.0 version: 3.12.0 + dayjs: + specifier: ^1.11.13 + version: 1.11.13 hono: specifier: ^4.6.1 version: 4.6.3 @@ -83,6 +98,10 @@ importers: packages: + '@acuminous/bitsyntax@0.1.2': + resolution: {integrity: sha512-29lUK80d1muEQqiUsSo+3A0yP6CdspgC95EnKBMi22Xlwt79i/En4Vr67+cXhU+cZjbti3TgGGC5wy1stIywVQ==} + engines: {node: '>=0.8'} + '@algolia/autocomplete-core@1.9.3': resolution: {integrity: sha512-009HdfugtGCdC4JdXUbVJClA0q0zh24yyePn+KUGk3rP7j8FEe/m5Yo/z65gn6nP/cM39PxpzqKrL7A6fP6PPw==} @@ -168,6 +187,9 @@ packages: '@braintree/sanitize-url@6.0.4': resolution: {integrity: sha512-s3jaWicZd0pkP0jf5ysyHUI/RE7MHos6qlToFcGWXVp+ykHOy77OUMrfbgJ9it2C5bow7OIQwYYaHjk9XlBQ2A==} + '@braintree/sanitize-url@7.1.0': + resolution: {integrity: sha512-o+UlMLt49RvtCASlOMW0AkHnabN9wR9rwCCherxO0yG4Npy34GkvrAqdXQvrhNs+jh+gkK8gB8Lf05qL/O7KWg==} + '@deno/kv-darwin-arm64@0.8.3': resolution: {integrity: sha512-edrjFTXrgo0utTezVbt8IsHIj9OsWJ3RtFl0lEhIfoI/Z1FwHg9wp3+LFOGLuQ8wz5nmnBQIBM3qDeXP7F7eOQ==} engines: {node: '>= 18'} @@ -373,6 +395,9 @@ packages: resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} engines: {node: '>=14'} + '@fedify/amqp@0.1.0-dev.8': + resolution: {integrity: sha512-GFDb8GLuyXtiBV9RtuCmFimNrglYDfDroZn9+Z9akhmTDp5lYhyfPPFQawSOvnwhyV36bgPIyFGZbaYznekZng==} + '@fedify/fedify@1.0.2': resolution: {integrity: sha512-OWVfahJRstzCOGSEDJ5CEppVHZyR9IfpFStj1WnedLE6rFoYZ94fZu7dQv4x0M1a1K3AfIiwvOAgcXldy21sWg==} @@ -541,6 +566,9 @@ packages: '@teidesu/deno-types@1.46.3': resolution: {integrity: sha512-JHuzaoYCjsYqcMoewjdCbnHGqN91puqit00m3Q3FbTETqbnreBNHirLhNbCgqNomAYMRTvGuHC7/HIh9jmBM2A==} + '@types/amqplib@0.10.5': + resolution: {integrity: sha512-/cSykxROY7BWwDoi4Y4/jLAuZTshZxd8Ey1QYa/VaXriMotBDoou7V/twJiOSHzU6t1Kp1AHAUXGCgqq+6DNeg==} + '@types/better-sqlite3@7.6.11': resolution: {integrity: sha512-i8KcD3PgGtGBLl3+mMYA8PdKkButvPyARxA7IQAd6qeslht13qxb1zzO8dRCtE7U3IoJS782zDBAeoKiM695kg==} @@ -728,6 +756,10 @@ packages: algoliasearch@4.24.0: resolution: {integrity: sha512-bf0QV/9jVejssFBmz2HQLxUadxk574t4iwjCKp5E7NBzwKkrDEhKPISIIjAU/p6K5qDx3qoeh4+26zWN1jmw3g==} + amqplib@0.10.4: + resolution: {integrity: sha512-DMZ4eCEjAVdX1II2TfIUpJhfKAuoCeDIo/YyETbfAqehHTXxxs7WOOd+N1Xxr4cKhx12y23zk8/os98FxlZHrw==} + engines: {node: '>=10'} + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -748,6 +780,9 @@ packages: brace-expansion@2.0.1: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + buffer-more-ints@1.0.0: + resolution: {integrity: sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg==} + bun-types@1.1.29: resolution: {integrity: sha512-En3/TzSPMPyl5UlUB1MHzHpcrZDakTm7mS203eLoX1fBoEa3PW+aSS8GAqVJ7Is/m34Z5ogL+ECniLY0uDaCPw==} @@ -796,6 +831,9 @@ packages: resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} engines: {node: '>=12.13'} + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + cose-base@1.0.3: resolution: {integrity: sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==} @@ -1079,6 +1117,9 @@ packages: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + internmap@1.0.1: resolution: {integrity: sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==} @@ -1098,6 +1139,9 @@ packages: resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} engines: {node: '>=12.13'} + isarray@0.0.1: + resolution: {integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==} + isexe@3.1.1: resolution: {integrity: sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==} engines: {node: '>=16'} @@ -1450,10 +1494,16 @@ packages: resolution: {integrity: sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==} engines: {node: '>=6.0.0'} + querystringify@2.2.0: + resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} + rdf-canonize@3.4.0: resolution: {integrity: sha512-fUeWjrkOO0t1rg7B2fdyDTvngj+9RlUyL92vOdiB7c0FPguWVsniIMjEtHH+meLBO9rzkUlUzBVXgWrjI8P9LA==} engines: {node: '>=12'} + readable-stream@1.1.14: + resolution: {integrity: sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==} + redis-errors@1.2.0: resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==} engines: {node: '>=4'} @@ -1465,6 +1515,9 @@ packages: regex@4.3.2: resolution: {integrity: sha512-kK/AA3A9K6q2js89+VMymcboLOlF5lZRCYJv3gzszXFHBr6kO6qLGzbm+UIugBEV8SMMKCTR59txoY6ctRHYVw==} + requires-port@1.0.0: + resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} + rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} @@ -1483,6 +1536,9 @@ packages: resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} engines: {node: '>=6'} + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} @@ -1513,6 +1569,9 @@ packages: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} + string_decoder@0.10.31: + resolution: {integrity: sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==} + stringify-entities@4.0.4: resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} @@ -1599,6 +1658,9 @@ packages: uri-template-router@0.0.16: resolution: {integrity: sha512-kvIuR8BtfL/VXFCM5hA7kjfYBdxMKQMmjOOA2zPUR1Xy7K+aVF2cVWMDaQEa2O74WN7zMloyvvmYjNJ38fVUew==} + url-parse@1.5.10: + resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} + url-template@3.1.1: resolution: {integrity: sha512-4oszoaEKE/mQOtAmdMWqIRHmkxWkUZMnXFnjQ5i01CuRSK3uluxcH1MRVVVWmhlnzT1SCDfKxxficm2G37qzCA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -1720,6 +1782,14 @@ packages: snapshots: + '@acuminous/bitsyntax@0.1.2': + dependencies: + buffer-more-ints: 1.0.0 + debug: 4.3.7 + safe-buffer: 5.1.2 + transitivePeerDependencies: + - supports-color + '@algolia/autocomplete-core@1.9.3(@algolia/client-search@4.24.0)(algoliasearch@4.24.0)(search-insights@2.17.2)': dependencies: '@algolia/autocomplete-plugin-algolia-insights': 1.9.3(@algolia/client-search@4.24.0)(algoliasearch@4.24.0)(search-insights@2.17.2) @@ -1840,6 +1910,8 @@ snapshots: '@braintree/sanitize-url@6.0.4': {} + '@braintree/sanitize-url@7.1.0': {} + '@deno/kv-darwin-arm64@0.8.3': optional: true @@ -1971,6 +2043,14 @@ snapshots: '@fastify/busboy@2.1.1': {} + '@fedify/amqp@0.1.0-dev.8(web-streams-polyfill@3.3.3)': + dependencies: + '@fedify/fedify': 1.0.2(web-streams-polyfill@3.3.3) + amqplib: 0.10.4 + transitivePeerDependencies: + - supports-color + - web-streams-polyfill + '@fedify/fedify@1.0.2(web-streams-polyfill@3.3.3)': dependencies: '@deno/shim-crypto': 0.3.1 @@ -2168,6 +2248,10 @@ snapshots: '@teidesu/deno-types@1.46.3': {} + '@types/amqplib@0.10.5': + dependencies: + '@types/node': 22.7.4 + '@types/better-sqlite3@7.6.11': dependencies: '@types/node': 22.7.4 @@ -2393,6 +2477,15 @@ snapshots: '@algolia/requester-node-http': 4.24.0 '@algolia/transporter': 4.24.0 + amqplib@0.10.4: + dependencies: + '@acuminous/bitsyntax': 0.1.2 + buffer-more-ints: 1.0.0 + readable-stream: 1.1.14 + url-parse: 1.5.10 + transitivePeerDependencies: + - supports-color + ansi-regex@5.0.1: {} argparse@2.0.1: {} @@ -2411,6 +2504,8 @@ snapshots: dependencies: balanced-match: 1.0.2 + buffer-more-ints@1.0.0: {} + bun-types@1.1.29: dependencies: '@types/node': 20.12.14 @@ -2446,6 +2541,8 @@ snapshots: dependencies: is-what: 4.1.16 + core-util-is@1.0.3: {} + cose-base@1.0.3: dependencies: layout-base: 1.0.2 @@ -2762,6 +2859,8 @@ snapshots: dependencies: safer-buffer: 2.1.2 + inherits@2.0.4: {} + internmap@1.0.1: {} internmap@2.0.3: {} @@ -2784,6 +2883,8 @@ snapshots: is-what@4.1.16: {} + isarray@0.0.1: {} + isexe@3.1.1: {} jsbi@4.3.0: {} @@ -3369,10 +3470,19 @@ snapshots: pvutils@1.1.3: {} + querystringify@2.2.0: {} + rdf-canonize@3.4.0: dependencies: setimmediate: 1.0.5 + readable-stream@1.1.14: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 0.0.1 + string_decoder: 0.10.31 + redis-errors@1.2.0: {} redis-parser@3.0.0: @@ -3381,6 +3491,8 @@ snapshots: regex@4.3.2: {} + requires-port@1.0.0: {} + rfdc@1.4.1: {} robust-predicates@3.0.2: {} @@ -3413,6 +3525,8 @@ snapshots: dependencies: mri: 1.2.0 + safe-buffer@5.1.2: {} + safer-buffer@2.1.2: {} search-insights@2.17.2: {} @@ -3442,6 +3556,8 @@ snapshots: is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 + string_decoder@0.10.31: {} + stringify-entities@4.0.4: dependencies: character-entities-html4: 2.1.0 @@ -3531,6 +3647,11 @@ snapshots: uri-template-router@0.0.16: {} + url-parse@1.5.10: + dependencies: + querystringify: 2.2.0 + requires-port: 1.0.0 + url-template@3.1.1: {} urlpattern-polyfill@10.0.0: {}