UNPKG

pg-transactional-outbox

Version:

A PostgreSQL based transactional outbox and inbox pattern implementation to support exactly once message processing (with at least once message delivery).

90 lines (83 loc) 2.58 kB
import { TransactionalMessage } from '../message/transactional-message'; export type ErrorCode = | 'DB_ERROR' | 'MESSAGE_HANDLING_FAILED' | 'MESSAGE_ERROR_HANDLING_FAILED' | 'GIVING_UP_MESSAGE_HANDLING' | 'POISONOUS_MESSAGE' | 'CONFLICTING_MESSAGE_HANDLERS' | 'NO_MESSAGE_HANDLER_REGISTERED' | 'LSN_ALREADY_PROCESSED' | 'LSN_NOT_PROCESSING' | 'LISTENER_STOPPED' | 'TIMEOUT' | 'MESSAGE_STORAGE_FAILED' | 'BATCH_PROCESSING_ERROR' | 'MESSAGE_CLEANUP_ERROR'; export interface ExtendedError extends Error { errorCode: ErrorCode; innerError?: Error; } /** An error that was raised from the transactional outbox/inbox library. Includes an error code. */ export class TransactionalOutboxInboxError extends Error implements ExtendedError { public innerError?: Error; constructor( message: string, public errorCode: ErrorCode, innerError?: unknown, ) { super(message); this.name = this.constructor.name; this.innerError = ensureError(innerError); } } /** An error that was raised when handling an outbox/inbox message. */ export class MessageError< T extends TransactionalMessage, > extends TransactionalOutboxInboxError { constructor( message: string, errorCode: ErrorCode, public messageObject: T, innerError?: unknown, ) { super(message, errorCode, innerError); this.name = this.constructor.name; } } /** * Returns the error as verified Error object or wraps the input as * ExtendedError with error code and potential innerError. * @param error The error variable to check * @param fallbackErrorCode The error code to use if the message is not already a TransactionalOutboxInboxError. * @param message The message object to use if the message is not a TransactionalOutboxInboxError. * @returns The error if the input was already an error otherwise a wrapped error. Enriched with the error code property. */ export const ensureExtendedError = ( error: unknown, fallbackErrorCode: ErrorCode, message?: TransactionalMessage, ): ExtendedError => { if (error instanceof TransactionalOutboxInboxError) { return error; } const err = ensureError(error) as ExtendedError; if (message) { return new MessageError(err.message, fallbackErrorCode, message, err); } else { err.errorCode = fallbackErrorCode; return err; } }; const ensureError = (error: unknown): Error | undefined => { if (error === null || error === undefined) { return undefined; } if (error instanceof Error) { return error; } return new Error(String(error)); };