メインコンテンツまでスキップ

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 します。

Backend code
// Emit once from the code that owns the action.
await this.squid.events().emit({ id: generateUUID(), type: 'user.signed-up', payload: { userId } });
Backend code
// 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を使用

仕組み​

  1. 信頼された backend code が、TriggerEvent({ id, type, payload } object)を指定して squid.events().emit() を呼び出します。
  2. Squid は event を core の internal event stream に enqueue します。emit() は event が処理された時点ではなく、enqueue された時点で resolve します。
  3. 同じ type の @eventHandler(type) で decorate されたすべての method が event を受け取ります。
  4. 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/backend package

ステップ 1: Event Handler を宣言する​

SquidService を拡張する service class を作成し、method を @eventHandler で decorate します。

Backend code
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() を呼び出します。

Backend code
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 です。

PropertyType説明
idstring一意の event ID。handler はこれを使用して再配信された event を de-duplicate できます。
typestringevent type。この event を受け取る @eventHandler subscriber を決定します。
payloadT任意の JSON-serializable event payload。

@eventHandler decorator​

@eventHandler<T>(type) は、指定した type の event 向け subscriber として SquidService method をマークします。method は完全な TriggerEvent<T> を受け取ります。同じ service 内または異なる service 内の複数の method が同じ type を subscribe でき、それぞれが独自の copy を受け取ります。

ParameterType必須説明
typestringはい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 が安全であるようにしてください。

Backend code
@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;
}
}

ベストプラクティス​

  1. handler を idempotency を考慮して設計する。 delivery は at-least-once であるため、同じ event に対して handler が複数回実行される可能性があります。event.id を使用して、すでに実行した作業を検出し skip してください。

  2. backend code からのみ emit する。 emit() には API key が必要なため、key が漏洩する client からではなく、executables またはその他の backend handler から trigger してください。

  3. payload は小さく、JSON-serializable に保つ。 payload に大きな object を埋め込むのではなく identifier を送信し、subscriber が必要なものを読み込むようにしてください。

  4. event type を namespace 化する。 order.placed や user.signed-up のような名前を使用すると、subscriber 数が増えても type を曖昧にせずに済みます。

関連項目​