// ./app-event-handlers/card.ts import type { SpecificEventHandler } from './base.ts';export const cardCreatedEventHandler: SpecificEventHandler<'card_created'> = async (ev) => { await sendNotificationToUsers();}// ./app-event-handlers/wire.tsimport type { SpecificEventHandler } from './base.ts';export const wireSentEventHandler: SpecificEventHandler<'wire_sent'> = async (ev) => { await sendNotificationToUsers();}
4. 定义汇总文件
./app-event-handlers/rollup.ts
export * from './card.ts';export * from './wire.ts';
5. 定义事件处理程序
./app-event-handlers/index.ts
import type { AppEventBase } from './base.ts';import * as AppEventHandlers from './rollup.ts';export type AppEvent = { [Key in keyof typeof EventHandlers]: (typeof EventHandlers)[Key] extends AppEventHandler<infer Ev extends AppEventBase> ? Ev : never;}[keyof typeof EventHandlers];export { AppEventHandlers };
6. 定义一个通用函数来记录事件
// ./record-app-event.tsimport { mqClient } from '@server/message-queue/client.ts';import type { AppEvent } from './app-event-handlers'export async function recordEvent<Ev extends AppEvent>(ev: Ev) { await mqClient.push('events', ev);}// ./some-random-service-file.tsimport { recordEvent } from './record-app-event.ts';await recordEvent({ type: 'card_created', data: { cardName: 'John Doe' } });
7. 导出一个处理队列事件处理程序的函数,该函数位于一个工作进程中。
./process-app-event.ts
import { AppEventHandlers, type AppEvent } from './app-event-handlers/index.ts';const appEventHandlerMap = new Map( Object.values(AppEventHandlers).map(item => [item.type, item.handler]));export async function processAppEventHandler(ev: AppEvent) { switch (ev.type) { case 'card_created': await AppEventHandlers.cardCreatedEventHandler(ev); break; case 'wire_sent': await AppEventHandlers.wireSentEventHandler(ev); break; default: // Compile-time & runtime check to ensure this case is unreachable (aka never) assertUnreachable(ev.type); }}
const eventName = `wire_${type}`; // Valid because type is a union between 'created' | 'sent', which are both defined eventsawait recordEvent({ type: eventName, data });
import { createRegistry } from '@/registry';const appEventHandlerDiscriminator = Symbol('app-event-handler');export const appEventHandlerRegistry = createRegistry<AppEventHandler<AppEventBase>>({ // When importing a module, a discriminator symbol to identify that an import is relevant to the registry discriminator: appEventHandlerDiscriminator, // The subextension to search for registryExtension: '.app-event-handler.ts', // Allows a lookup key to be derived from a module getKey: (mod) => mod.type,});export interface AppEventBase { type: string; data: unknown;}/** * Define an interface that exposes a `$discriminator` prop */export interface AppEventHandler<Ev extends AppEventBase> { $discriminator: typeof appEventHandlerDiscriminator; type: Ev['type']; handler: (data: Ev['data']) => Promise<void>;}/** * Define the method we'll actually use to create each event handler*/export function createAppEventHandler<Ev extends AppEventBase>( event: Ev['type'], handler: (data: Ev['data']) => Promise<void>): AppEventHandler<Ev> { return { $discriminator: appEventHandlerDiscriminator, type: event, handler }}
import { mqClient } from '@server/message-queue/client.ts';import type { AppEvent } from './app-event-handlers'export async function recordEvent<Ev extends AppEvent>( ev: AppEventHandler<Ev>, data: Ev) { await mqClient.push('events', { type: ev.type, data });}
4. 导出一个处理队列事件处理程序的函数,该函数位于一个工作进程中。
./process-app-event.ts
import { type AppEventBase, appEventHandlerRegistry } from './app-event-handler.registry';export async function processAppEventHandler(ev: AppEventBase) { // Here, the registry allows us to look up by the serialized type name, and then call the corresponding handler. const item = appEventHandlerRegistry.get(ev.type, { throws: true }); await item.handler(ev);}