Unverified Commit 4057f08f authored by Hong Minhee's avatar Hong Minhee
Browse files

Separating message processing from the main process

parent f4e245b4
Loading
Loading
Loading
Loading
+79 −0
Original line number Diff line number Diff line
@@ -222,3 +222,82 @@ const federation = createFederation<void>({
> If your [inbox listeners](./inbox.md) are CPU-bound, you should consider
> running multiple nodes of your application so that each node can process
> messages in parallel with the shared message queue.


Separating message processing from the main process
---------------------------------------------------

*This API is available since Fedify 0.12.0.*

On high-traffic servers, it's common to separate message processing from
the main server process to avoid blocking the main event loop.  To achieve this,
you can use the `~CreateFederationOptions.manuallyStartQueue` option and
`Federation.startQueue()` method:

::: code-group

~~~~ typescript{11-15} twoslash [Deno]
import type { KvStore } from "@fedify/fedify";
// ---cut-before---
import { createFederation } from "@fedify/fedify";
import { RedisMessageQueue } from "@fedify/redis";
import Redis from "ioredis";

const federation = createFederation<void>({
  queue: new RedisMessageQueue(() => new Redis()),
  manuallyStartQueue: true,  // [!code highlight]
  // ... other options
  // ---cut-start---
  kv: null as unknown as KvStore,
  // ---cut-end---
});

// Start the message queue manually only in worker nodes.
// On non-worker nodes, the queue won't be started.
if (Deno.env.get("NODE_TYPE") === "worker") {
  await federation.startQueue();
}
~~~~

~~~~ typescript{12-16} twoslash [Node.js/Bun]
import type { KvStore } from "@fedify/fedify";
// ---cut-before---
import { createFederation } from "@fedify/fedify";
import { RedisMessageQueue } from "@fedify/redis";
import Redis from "ioredis";
import { env } from "node:process";

const federation = createFederation<void>({
  queue: new RedisMessageQueue(() => new Redis()),
  manuallyStartQueue: true,  // [!code highlight]
  // ... other options
  // ---cut-start---
  kv: null as unknown as KvStore,
  // ---cut-end---
});

// Start the message queue manually only in worker nodes.
// On non-worker nodes, the queue won't be started.
if (env.NODE_TYPE === "worker") {
  await federation.startQueue();
}
~~~~

:::

The key point is to ensure that messages are enqueued only from
the `NODE_TYPE=web` nodes, and messages are processed only from
the `NODE_TYPE=worker` nodes:

| `NODE_TYPE` | Process messages? | Enqueue messages? |
|-------------|-------------------|-------------------|
| `web`       | Do not process    | Enqueue           |
| `worker`    | Process           | Do not enqueue    |

This separation allows you to scale your application by running multiple worker
nodes that process messages concurrently.  It also helps to keep the main
server process responsive by offloading message processing to worker nodes.

> [!NOTE]
> To ensure that messages are enqueued only from the `NODE_TYPE=web` nodes,
> you should not place the `NODE_TYPE=worker` nodes behind a load balancer.
+1 −1
Original line number Diff line number Diff line
{
  "devDependencies": {
    "@deno/kv": "^0.8.2",
    "@fedify/fedify": "1.0.0-dev.407",
    "@fedify/fedify": "1.0.0-dev.408",
    "@fedify/redis": "^0.1.1",
    "@hono/node-server": "^1.12.2",
    "@js-temporal/polyfill": "^0.4.4",
+5 −5
Original line number Diff line number Diff line
@@ -12,8 +12,8 @@ importers:
        specifier: ^0.8.2
        version: 0.8.2
      '@fedify/fedify':
        specifier: 1.0.0-dev.407
        version: 1.0.0-dev.407(web-streams-polyfill@3.3.3)
        specifier: 1.0.0-dev.408
        version: 1.0.0-dev.408(web-streams-polyfill@3.3.3)
      '@fedify/redis':
        specifier: ^0.1.1
        version: 0.1.1(web-streams-polyfill@3.3.3)
@@ -370,8 +370,8 @@ packages:
  '@fedify/fedify@0.10.2':
    resolution: {integrity: sha512-GKxm+NZ1zNPJ9HTbTW+Y2o/HT3Rk6ly+j/GJfjXBFiwm391Ni56VYC8ON/KQsFdFYIp+eNMn1hWr0RbFtMwoOg==}

  '@fedify/fedify@1.0.0-dev.407':
    resolution: {integrity: sha512-VYbsOkaS+lsBg3JgOTXcG4GDyCD7GcOBvjn1f/K37EDqPUjmuqPJuhBquiTz+EffFpHKqJ10A0i78rHufa8U7g==}
  '@fedify/fedify@1.0.0-dev.408':
    resolution: {integrity: sha512-Lln5Ln0lCCgrskhVN4YibDBgTeuHA2nyT2r3szeXi81j6vNGxpRzdHQ+0wBSglrR17X+EtHlMltsrCCmXbDFsQ==}

  '@fedify/redis@0.1.1':
    resolution: {integrity: sha512-oKhOVYLRwkRf/tuePoT3CnwXUKm5rTE7hDg8/qfVo/txmydPPptXzPG10kL24zCv8t18FwmyaE0LlcrUrxd6FQ==}
@@ -1974,7 +1974,7 @@ snapshots:
    transitivePeerDependencies:
      - web-streams-polyfill

  '@fedify/fedify@1.0.0-dev.407(web-streams-polyfill@3.3.3)':
  '@fedify/fedify@1.0.0-dev.408(web-streams-polyfill@3.3.3)':
    dependencies:
      '@deno/shim-crypto': 0.3.1
      '@deno/shim-deno': 0.18.2