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).

56 lines (53 loc) 2.33 kB
import { isPgSerializationError } from '../common/database'; import { ExtendedError } from '../common/error'; import { FullListenerConfig } from '../common/listener-config'; import { StoredTransactionalMessage } from '../message/transactional-message'; /** * Decides if a message should be attempted again and what the maximum number of * attempts for that message should be. */ export interface MessageRetryStrategy { /** * Checks if the message should be retried after an error occurred. The number * of processing attempts (including the current) is available in the message * object. * @param message The stored message * @param error The error that was thrown from the message handler or error handler * @param source If the error was thrown from the message handler, from the error handler, or from the code handling errors in the error handler. * @returns true if the message should be retried, otherwise false. */ ( message: StoredTransactionalMessage, error: ExtendedError, source: 'message-handler' | 'error-handler' | 'error-handler-error', ): boolean; } /** * Get the default message retry strategy. This strategy checks that the maximum * of finished attempts is not exceeded. The number can be defined in the * `config.settings.maxAttempts` variable. If the error is a PostgreSQL * serialization error it will be retried up to 100 times (or up to maxAttempts * whatever is larger). If another error was thrown from the code handling * errors in the error handler the message is not retired. */ export const defaultMessageRetryStrategy = ( config: FullListenerConfig, ): MessageRetryStrategy => { return ( message: StoredTransactionalMessage, error: ExtendedError, source: 'message-handler' | 'error-handler' | 'error-handler-error', ): boolean => { if (isPgSerializationError(error.innerError)) { // retry PostgreSQL serialization/deadlock failures up to 100 attempts return ( message.startedAttempts <= Math.max(config.settings.maxAttempts, 100) ); } if (source === 'error-handler-error') { // If even the code that handles errors in the error handler throws an error the message is not retried. return false; } return message.finishedAttempts < config.settings.maxAttempts; }; };