@arturwojnar/hermes-postgresql
Version:
Production-Ready TypeScript Outbox Pattern for PostgreSQL
67 lines • 2.3 kB
JavaScript
import { Duration } from '@arturwojnar/hermes';
import { EventEmitter } from 'events';
class TransactionManager extends EventEmitter {
publish;
currentTransaction;
lastAcknowledgedLsn;
isProcessing = false;
processingTimeout;
constructor(publish, initialLsn, processingTimeout = Duration.ofSeconds(30)) {
super();
this.publish = publish;
this.lastAcknowledgedLsn = initialLsn;
this.processingTimeout = processingTimeout;
}
beginTransaction(transaction) {
if (this.currentTransaction) {
throw new Error('Previous transaction not completed');
}
this.currentTransaction = { ...transaction, results: [] };
}
addInsert(result) {
if (!this.currentTransaction) {
throw new Error('No active transaction');
}
this.currentTransaction.results.push(result);
}
async commitTransaction() {
if (!this.currentTransaction) {
throw new Error('No active transaction to commit');
}
const transaction = this.currentTransaction;
const finalLsn = this.currentTransaction.lsn;
this.currentTransaction = undefined;
try {
for (const result of transaction.results) {
try {
await this.publish({
position: result.position,
eventType: result.eventType,
lsn: transaction.lsn,
event: JSON.parse(result.payload),
});
}
catch (error) {
this.emit('error', { transaction, error });
this.currentTransaction = transaction;
throw error;
}
}
this.lastAcknowledgedLsn = finalLsn;
this.emit('transactionProcessed', transaction);
}
catch (error) {
throw error;
}
}
getLastAcknowledgedLsn() {
return this.lastAcknowledgedLsn || '0/00000000';
}
async retry() {
if (this.currentTransaction && !this.isProcessing) {
await this.commitTransaction();
}
}
}
export { TransactionManager };
//# sourceMappingURL=TransactionManager.js.map