Events
信頼された backend code から、1 つ以上の backend handler に event を broadcast します。
Events を使用する理由
単一の backend action が、複数の独立した follow-up を trigger する必要があることはよくあります。たとえば新規 signup では、welcome email の送信、resource の provision、analytics の更新が必要になる場合があります。これらすべてを signup function に組み込むと、無関係な関心事が結合され、それぞれの変更が難しくなります。
events を使用すると、action は 1 つの event を emit し、各関心事は独立して subscribe します。
// Emit once from the code that owns the action.
await this.squid.events().emit({ id: generateUUID(), type: 'user.signed-up', payload: { userId } });
// Handle it in as many independent subscribers as you need.
@eventHandler<{ userId: string }>('user.signed-up')
async sendWelcomeEmail(event: TriggerEvent<{ userId: string }>): Promise<void> {
await this.emailWelcome(event.payload.userId);
}
概要
Events は、Squid backend 内の軽量な publish/subscribe mechanism です。信頼された server-side code が squid.events().emit() で typed event を emit すると、その event type 向けの @eventHandler で decorate されたすべての backend method が copy を受け取ります。Events は Squid core の internal event stream を介して配信されるため、queue connector を構成する必要はありません。
Events を使用する場合
| ユースケース | 推奨 |
|---|---|
| 1 つの server-side action を複数の独立した handler に fan-out する | ✅ Events |
| queue topic に publish された message(client からのものを含む)を処理する | Queue message handlersを使用 |
| database の変更に反応する | Triggersを使用 |
| client から function を呼び出す | Executablesを使用 |
| schedule に従って code を実行する | Schedulersを使用 |
仕組み
- 信頼された backend code が、
TriggerEvent({ id, type, payload }object)を指定してsquid.events().emit()を呼び出します。 - Squid は event を core の internal event stream に enqueue します。
emit()は event が処理された時点ではなく、enqueue された時点で resolve します。 - 同じ
typeの@eventHandler(type)で decorate されたすべての method が event を受け取ります。 - delivery は at-least-once であり ordering guarantee はありません。そのため handler が同じ event に対して複数回実行されることがあり、同じ type の event が順不同で到着する場合があります。
Events と Queue Message Handlers
どちらも message を backend handler に配信しますが、解決する問題は異なります。
- Events は type ごとのすべての
@eventHandlerに broadcast され、queue connector の構成を必要としない Squid の internal event stream 上で実行されます。emit には API key authentication が必要なため、event は常に信頼された backend code から送信されます。 - Queue message handlers は、名前付き queue topic(built-in queue または Kafka などの external connector)から message を consume し、client からも生成できます。
クイックスタート
前提条件
squid initで初期化された Squid backend project- NPM からインストールされた
@squidcloud/backendpackage
ステップ 1: Event Handler を宣言する
SquidService を拡張する service class を作成し、method を @eventHandler で decorate します。
import { SquidService, eventHandler, TriggerEvent } from '@squidcloud/backend';
interface OrderPlaced {
orderId: string;
customerEmail: string;
}
export class ExampleService extends SquidService {
// Runs once for every 'order.placed' event that is emitted.
@eventHandler<OrderPlaced>('order.placed')
async onOrderPlaced(event: TriggerEvent<OrderPlaced>): Promise<void> {
const { orderId, customerEmail } = event.payload;
// Email the customer using your own email helper.
await this.sendOrderConfirmationEmail(customerEmail, orderId);
}
}
ステップ 2: 信頼された backend code から Event を emit する
emit には API key authentication が必要なため、backend code で実行する必要があります。API key が漏洩するため、client では決して実行しないでください。this.squid を使用して backend Squid instance にアクセスし、events().emit() を呼び出します。
import { SquidService, executable, TriggerEvent } from '@squidcloud/backend';
import { generateUUID } from '@squidcloud/client';
export class ExampleService extends SquidService {
@executable()
async placeOrder(orderId: string, customerEmail: string): Promise<void> {
// Persist the order first, then announce it.
const event: TriggerEvent<OrderPlaced> = {
id: generateUUID(), // Unique per event; used to trace and de-duplicate.
type: 'order.placed',
payload: { orderId, customerEmail },
};
await this.squid.events().emit(event);
}
}
ステップ 3: backend を起動または deploy する
ローカル開発では、Squid CLI を使用して backend をローカルで実行します。
squid start
cloud に deploy するには、backend の deployを参照してください。
ステップ 4: 検証する
emit を trigger し(たとえば上記の executable を呼び出します)、Squid Console の log で handler が呼び出されたことを確認します。
コアコンセプト
TriggerEvent object
すべての event は、3 つの field を持つ TriggerEvent です。
| Property | Type | 説明 |
|---|---|---|
id | string | 一意の event ID。handler はこれを使用して再配信された event を de-duplicate できます。 |
type | string | event type。この event を受け取る @eventHandler subscriber を決定します。 |
payload | T | 任意の JSON-serializable event payload。 |
@eventHandler decorator
@eventHandler<T>(type) は、指定した type の event 向け subscriber として SquidService method をマークします。method は完全な TriggerEvent<T> を受け取ります。同じ service 内または異なる service 内の複数の method が同じ type を subscribe でき、それぞれが独自の copy を受け取ります。
| Parameter | Type | 必須 | 説明 |
|---|---|---|---|
type | string | はい | subscribe する event type。 |
Event の emit
squid.events().emit(event) は TriggerEvent を publish します。API key authentication が必要であるため、backend code でのみ実行されます。返される promise は、subscriber が処理した時点ではなく event が enqueue された時点で resolve します。
Delivery Semantics
Events は ordering guarantee のない at-least-once で配信されます。handler は、同じ event を複数回受け取ることがあり、同じ type の event が順不同で到着することがあります。handler は idempotent かつ order-independent になるよう設計してください。
Error Handling
event handler が error を throw すると、その error は Squid Console に log されます。delivery は at-least-once であるため、event は再配信される場合があります。handler logic を try/catch でラップし、retry が安全であるようにしてください。
@eventHandler<OrderPlaced>('order.placed')
async onOrderPlaced(event: TriggerEvent<OrderPlaced>): Promise<void> {
try {
await this.processOrder(event.payload);
} catch (error) {
// event.id identifies the specific event across redeliveries.
console.error(`Failed to handle order event ${event.id}:`, error);
throw error;
}
}
ベストプラクティス
-
handler を idempotency を考慮して設計する。 delivery は at-least-once であるため、同じ event に対して handler が複数回実行される可能性があります。
event.idを使用して、すでに実行した作業を検出し skip してください。 -
backend code からのみ emit する。
emit()には API key が必要なため、key が漏洩する client からではなく、executables またはその他の backend handler から trigger してください。 -
payload は小さく、JSON-serializable に保つ。 payload に大きな object を埋め込むのではなく identifier を送信し、subscriber が必要なものを読み込むようにしてください。
-
event type を namespace 化する。
order.placedやuser.signed-upのような名前を使用すると、subscriber 数が増えても type を曖昧にせずに済みます。
関連項目
- Queue message handlers - queue topic から message を consume する
- Triggers - database の変更に反応する
- Executables - client から backend function を呼び出す
- Schedulers - schedule に従って code を実行する