UNPKG

@axinom/mosaic-transactional-inbox-outbox

Version:

This library encapsulates the Mosaic based transactional inbox and outbox pattern

112 lines (106 loc) 3.6 kB
import { MessagingSettings } from '@axinom/mosaic-message-bus-abstractions'; import { randomUUID } from 'node:crypto'; import { DatabaseClient, ListenerConfig, TransactionalMessage, initializeMessageStorage, } from 'pg-transactional-outbox'; import { InboxOutboxLogger, RabbitMqMessageFields, RabbitMqMessageProperties, } from '../common'; import { TransactionalLogMapper } from '../transactional-log-mapper'; /** * Helper interface for inbox message metadata, that includes the message * envelope overrides for e.g. the auth_token. */ export interface InboxMessageMetadata { /** overrides for Mosaic Envelope properties (ex: auth_token) */ authToken?: string; messageVersion?: string; messageContext?: unknown; fields?: RabbitMqMessageFields; properties?: RabbitMqMessageProperties; [key: string]: unknown; } /** * Add additional data to the message that is going to be stored * @param metadata Messaging transport related metadata * @param concurrency Define if the message must be sent in the sequential order it was added or if it can be sent in parallel with others. * @param lockedUntil The date and time in ISO 8601 "internet time" UTC format (e.g. "2023-10-17T11:48:14Z") until when the message cannot be sent out * @param segment Can be set to allow processing of messages with different segments in parallel. * @param createdAt The create date of the message if it is available. * @param messageId The unique ID of the message. If not specified - random UUID will be used */ export interface OptionalInboxData { metadata?: InboxMessageMetadata; concurrency?: 'sequential' | 'parallel'; lockedUntil?: string; segment?: string; createdAt?: string; messageId?: string; } /** * Function to store the transactional inbox message * @param messageId The unique ID of the message * @param aggregateId The (database) ID of the aggregate type or use the const UNKNOWN_AGGREGATE_ID or MULTIPLE_AGGREGATE_IDS values. * @param messagingSettings The messaging related settings object * @param payload The payload of the message * @param client The database client to use to store the message * @param optionalData Add additional data to the message that is going to be stored */ export type StoreInboxMessage = <T>( aggregateId: string, messagingSettings: Pick<MessagingSettings, 'messageType' | 'aggregateType'>, payload: T, client: DatabaseClient, optionalData?: OptionalInboxData, ) => Promise<void>; /** * Returns a function to store transactional inbox messages directly for service * internal messaging. * See the StoreInboxMessage type for parameter descriptions. */ export const setupInboxStorage = ( listenerConfig: ListenerConfig, logger: InboxOutboxLogger, config: { logLevel: string }, ): StoreInboxMessage => { const storage = initializeMessageStorage( listenerConfig, new TransactionalLogMapper(logger, config.logLevel), ); return async <T>( aggregateId: string, { aggregateType, messageType, }: Pick<MessagingSettings, 'aggregateType' | 'messageType'>, payload: T, client: DatabaseClient, { metadata, concurrency, lockedUntil, segment, createdAt, messageId, }: OptionalInboxData = {}, ) => { const message: TransactionalMessage = { id: messageId ?? randomUUID(), aggregateId, payload, aggregateType, messageType, metadata, concurrency: concurrency ?? 'parallel', lockedUntil, segment, createdAt, }; await storage(message, client); }; };