@outbox-event-bus/postgres-drizzle-outbox 2.0.3 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -5
- package/dist/index.cjs +26 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -7
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +21 -7
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +26 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/postgres-drizzle-outbox.ts +7 -7
- package/src/transaction-storage.ts +30 -0
package/README.md
CHANGED
|
@@ -194,13 +194,13 @@ async function createUser(user: any) {
|
|
|
194
194
|
return await db.transaction(async (tx) => {
|
|
195
195
|
return await als.run(tx, async () => {
|
|
196
196
|
await tx.insert(users).values(user);
|
|
197
|
-
|
|
197
|
+
|
|
198
198
|
// Bus automatically uses transaction from ALS
|
|
199
|
-
await bus.emit({
|
|
200
|
-
type: 'user.created',
|
|
201
|
-
payload: user
|
|
199
|
+
await bus.emit({
|
|
200
|
+
type: 'user.created',
|
|
201
|
+
payload: user
|
|
202
202
|
});
|
|
203
|
-
|
|
203
|
+
|
|
204
204
|
return user;
|
|
205
205
|
});
|
|
206
206
|
});
|
|
@@ -210,6 +210,40 @@ async function createUser(user: any) {
|
|
|
210
210
|
> [!TIP]
|
|
211
211
|
> AsyncLocalStorage eliminates the need to pass transactions through your call stack, improving code clarity.
|
|
212
212
|
|
|
213
|
+
### 4. Typed Schema Support
|
|
214
|
+
|
|
215
|
+
`PostgresDrizzleOutbox` accepts a generic schema type parameter, so you can pass your typed Drizzle database instance directly without casting:
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
import { drizzle } from 'drizzle-orm/postgres-js';
|
|
219
|
+
import postgres from 'postgres';
|
|
220
|
+
import * as schema from './schema';
|
|
221
|
+
import { PostgresDrizzleOutbox } from '@outbox-event-bus/postgres-drizzle-outbox';
|
|
222
|
+
|
|
223
|
+
const client = postgres(process.env.DATABASE_URL!);
|
|
224
|
+
const db = drizzle(client, { schema });
|
|
225
|
+
|
|
226
|
+
// Schema type is inferred — no need to cast db
|
|
227
|
+
const outbox = new PostgresDrizzleOutbox({
|
|
228
|
+
db,
|
|
229
|
+
getTransaction: () => transactionManager.getCurrentTransaction()
|
|
230
|
+
});
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
The `createDrizzleTransactionStorage` helper also supports typed schemas:
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
import { createDrizzleTransactionStorage } from '@outbox-event-bus/postgres-drizzle-outbox';
|
|
237
|
+
import * as schema from './schema';
|
|
238
|
+
|
|
239
|
+
const { withTransaction, getTransaction } = createDrizzleTransactionStorage<typeof schema>();
|
|
240
|
+
|
|
241
|
+
const outbox = new PostgresDrizzleOutbox({
|
|
242
|
+
db,
|
|
243
|
+
getTransaction
|
|
244
|
+
});
|
|
245
|
+
```
|
|
246
|
+
|
|
213
247
|
## Custom Table Schemas
|
|
214
248
|
|
|
215
249
|
The adapter supports custom table definitions, enabling:
|
package/dist/index.cjs
CHANGED
|
@@ -148,18 +148,44 @@ var PostgresDrizzleOutbox = class {
|
|
|
148
148
|
|
|
149
149
|
//#endregion
|
|
150
150
|
//#region src/transaction-storage.ts
|
|
151
|
+
function createDrizzleTransactionStorage() {
|
|
152
|
+
const storage = new node_async_hooks.AsyncLocalStorage();
|
|
153
|
+
async function withTransaction(db, fn) {
|
|
154
|
+
return db.transaction(async (tx) => {
|
|
155
|
+
return storage.run(tx, () => fn(tx));
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
function getTransaction() {
|
|
159
|
+
return storage.getStore();
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
storage,
|
|
163
|
+
withTransaction,
|
|
164
|
+
getTransaction
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* @deprecated Use `createDrizzleTransactionStorage()` for type-safe schema support.
|
|
169
|
+
*/
|
|
151
170
|
const drizzleTransactionStorage = new node_async_hooks.AsyncLocalStorage();
|
|
171
|
+
/**
|
|
172
|
+
* @deprecated Use `createDrizzleTransactionStorage()` for type-safe schema support.
|
|
173
|
+
*/
|
|
152
174
|
async function withDrizzleTransaction(db, fn) {
|
|
153
175
|
return db.transaction(async (tx) => {
|
|
154
176
|
return drizzleTransactionStorage.run(tx, () => fn(tx));
|
|
155
177
|
});
|
|
156
178
|
}
|
|
179
|
+
/**
|
|
180
|
+
* @deprecated Use `createDrizzleTransactionStorage()` for type-safe schema support.
|
|
181
|
+
*/
|
|
157
182
|
function getDrizzleTransaction() {
|
|
158
183
|
return () => drizzleTransactionStorage.getStore();
|
|
159
184
|
}
|
|
160
185
|
|
|
161
186
|
//#endregion
|
|
162
187
|
exports.PostgresDrizzleOutbox = PostgresDrizzleOutbox;
|
|
188
|
+
exports.createDrizzleTransactionStorage = createDrizzleTransactionStorage;
|
|
163
189
|
exports.drizzleTransactionStorage = drizzleTransactionStorage;
|
|
164
190
|
exports.getDrizzleTransaction = getDrizzleTransaction;
|
|
165
191
|
exports.outboxEvents = outboxEvents;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["PollingService","EventStatus","failedEvent: FailedBusEvent","error: unknown","AsyncLocalStorage"],"sources":["../src/schema.ts","../src/postgres-drizzle-outbox.ts","../src/transaction-storage.ts"],"sourcesContent":["import {\n integer,\n jsonb,\n pgEnum,\n pgTable,\n text,\n timestamp,\n uuid,\n} from \"drizzle-orm/pg-core\"\n\n\nexport const outboxStatusEnum = pgEnum(\"outbox_status\", [\n \"created\",\n \"active\",\n \"completed\",\n \"failed\",\n])\n\nexport const outboxEvents = pgTable(\"outbox_events\", {\n id: uuid(\"id\").primaryKey(),\n type: text(\"type\").notNull(),\n payload: jsonb(\"payload\").notNull(),\n occurredAt: timestamp(\"occurred_at\").notNull(),\n status: outboxStatusEnum(\"status\").notNull().default(\"created\"),\n retryCount: integer(\"retry_count\").notNull().default(0),\n lastError: text(\"last_error\"),\n nextRetryAt: timestamp(\"next_retry_at\"),\n createdOn: timestamp(\"created_on\").notNull().defaultNow(),\n startedOn: timestamp(\"started_on\"),\n completedOn: timestamp(\"completed_on\"),\n keepAlive: timestamp(\"keep_alive\"),\n expireInSeconds: integer(\"expire_in_seconds\").notNull().default(300),\n})\n\nexport const outboxEventsArchive = pgTable(\"outbox_events_archive\", {\n id: uuid(\"id\").primaryKey(),\n type: text(\"type\").notNull(),\n payload: jsonb(\"payload\").notNull(),\n occurredAt: timestamp(\"occurred_at\").notNull(),\n status: outboxStatusEnum(\"status\").notNull(),\n retryCount: integer(\"retry_count\").notNull(),\n lastError: text(\"last_error\"),\n createdOn: timestamp(\"created_on\").notNull(),\n startedOn: timestamp(\"started_on\"),\n completedOn: timestamp(\"completed_on\").notNull(),\n})\n","import { and, eq, inArray, lt, or, sql } from \"drizzle-orm\"\nimport type { PostgresJsDatabase } from \"drizzle-orm/postgres-js\"\nimport {\n type BusEvent,\n type ErrorHandler,\n EventStatus,\n type FailedBusEvent,\n formatErrorMessage,\n type IOutbox,\n type OutboxConfig,\n PollingService,\n reportEventError,\n} from \"outbox-event-bus\"\nimport { outboxEvents, outboxEventsArchive } from \"./schema\"\n\nexport interface PostgresDrizzleOutboxConfig extends OutboxConfig {\n db: PostgresJsDatabase<Record<string, unknown>>\n getTransaction?: (() => PostgresJsDatabase<Record<string, unknown>> | undefined) | undefined\n tables?: {\n outboxEvents: typeof outboxEvents\n outboxEventsArchive: typeof outboxEventsArchive\n }\n}\n\nexport class PostgresDrizzleOutbox implements IOutbox<PostgresJsDatabase<Record<string, unknown>>> {\n private readonly config: Required<PostgresDrizzleOutboxConfig>\n private readonly poller: PollingService\n\n constructor(config: PostgresDrizzleOutboxConfig) {\n this.config = {\n batchSize: config.batchSize ?? 50,\n pollIntervalMs: config.pollIntervalMs ?? 1000,\n maxRetries: config.maxRetries ?? 5,\n baseBackoffMs: config.baseBackoffMs ?? 1000,\n processingTimeoutMs: config.processingTimeoutMs ?? 30000,\n maxErrorBackoffMs: config.maxErrorBackoffMs ?? 30000,\n db: config.db,\n getTransaction: config.getTransaction,\n tables: config.tables ?? {\n outboxEvents,\n outboxEventsArchive,\n },\n }\n\n this.poller = new PollingService({\n pollIntervalMs: this.config.pollIntervalMs,\n baseBackoffMs: this.config.baseBackoffMs,\n maxErrorBackoffMs: this.config.maxErrorBackoffMs,\n processBatch: (handler) => this.processBatch(handler),\n })\n }\n\n async publish(\n events: BusEvent[],\n transaction?: PostgresJsDatabase<Record<string, unknown>>\n ): Promise<void> {\n const executor = transaction ?? this.config.getTransaction?.() ?? this.config.db\n\n await executor.insert(this.config.tables.outboxEvents).values(\n events.map((event) => ({\n id: event.id,\n type: event.type,\n payload: event.payload,\n occurredAt: event.occurredAt,\n status: EventStatus.CREATED,\n }))\n )\n }\n\n async getFailedEvents(): Promise<FailedBusEvent[]> {\n const events = await this.config.db\n .select()\n .from(this.config.tables.outboxEvents)\n .where(eq(this.config.tables.outboxEvents.status, EventStatus.FAILED))\n .orderBy(sql`${this.config.tables.outboxEvents.occurredAt} DESC`)\n .limit(100)\n\n return events.map((event) => {\n const failedEvent: FailedBusEvent = {\n id: event.id,\n type: event.type,\n payload: event.payload as any,\n occurredAt: event.occurredAt,\n retryCount: event.retryCount,\n }\n if (event.lastError) failedEvent.error = event.lastError\n if (event.startedOn) failedEvent.lastAttemptAt = event.startedOn\n return failedEvent\n })\n }\n\n async retryEvents(eventIds: string[]): Promise<void> {\n await this.config.db\n .update(this.config.tables.outboxEvents)\n .set({\n status: EventStatus.CREATED,\n retryCount: 0,\n nextRetryAt: null,\n lastError: null,\n })\n .where(inArray(this.config.tables.outboxEvents.id, eventIds))\n }\n\n start(handler: (event: BusEvent) => Promise<void>, onError: ErrorHandler): void {\n this.poller.start(handler, onError)\n }\n\n async stop(): Promise<void> {\n await this.poller.stop()\n }\n\n private async processBatch(handler: (event: BusEvent) => Promise<void>) {\n const now = new Date()\n\n const lockedEvents = await this.config.db.transaction(async (transaction) => {\n const events = await transaction\n .select()\n .from(this.config.tables.outboxEvents)\n .where(\n or(\n eq(this.config.tables.outboxEvents.status, EventStatus.CREATED),\n and(\n eq(this.config.tables.outboxEvents.status, EventStatus.FAILED),\n lt(this.config.tables.outboxEvents.retryCount, this.config.maxRetries),\n lt(this.config.tables.outboxEvents.nextRetryAt, now)\n ),\n and(\n eq(this.config.tables.outboxEvents.status, EventStatus.ACTIVE),\n lt(\n this.config.tables.outboxEvents.keepAlive,\n sql`${now.toISOString()}::timestamp - make_interval(secs => ${this.config.tables.outboxEvents.expireInSeconds})`\n )\n )\n )\n )\n .limit(this.config.batchSize)\n .for(\"update\", { skipLocked: true })\n\n if (events.length === 0) return []\n\n const eventIds = events.map((event) => event.id)\n\n await transaction\n .update(this.config.tables.outboxEvents)\n .set({\n status: EventStatus.ACTIVE,\n startedOn: now,\n keepAlive: now,\n })\n .where(inArray(this.config.tables.outboxEvents.id, eventIds))\n\n return events\n })\n\n if (lockedEvents.length === 0) return\n\n // 2. Process events outside of the transaction\n for (const event of lockedEvents) {\n try {\n await handler(event)\n\n // use the main db connection for individual updates to avoid long transactions\n await this.config.db.transaction(async (transaction) => {\n await transaction.insert(this.config.tables.outboxEventsArchive).values({\n id: event.id,\n type: event.type,\n payload: event.payload as any,\n occurredAt: event.occurredAt,\n status: EventStatus.COMPLETED,\n retryCount: event.retryCount,\n createdOn: event.createdOn,\n startedOn: now,\n completedOn: new Date(),\n })\n await transaction\n .delete(this.config.tables.outboxEvents)\n .where(eq(this.config.tables.outboxEvents.id, event.id))\n })\n } catch (error: unknown) {\n const retryCount = event.retryCount + 1\n reportEventError(this.poller.onError, error, event, retryCount, this.config.maxRetries)\n\n const delay = this.poller.calculateBackoff(retryCount)\n await this.config.db\n .update(this.config.tables.outboxEvents)\n .set({\n status: EventStatus.FAILED,\n retryCount,\n lastError: formatErrorMessage(error),\n nextRetryAt: new Date(Date.now() + delay),\n })\n .where(eq(this.config.tables.outboxEvents.id, event.id))\n }\n }\n }\n}\n","import { AsyncLocalStorage } from \"node:async_hooks\"\nimport type { PostgresJsDatabase } from \"drizzle-orm/postgres-js\"\n\nexport const drizzleTransactionStorage = new AsyncLocalStorage<\n PostgresJsDatabase<Record<string, unknown>>\n>()\n\nexport async function withDrizzleTransaction<T>(\n db: PostgresJsDatabase<Record<string, unknown>>,\n fn: (tx: PostgresJsDatabase<Record<string, unknown>>) => Promise<T>\n): Promise<T> {\n return db.transaction(async (tx) => {\n return drizzleTransactionStorage.run(tx, () => fn(tx))\n })\n}\n\nexport function getDrizzleTransaction(): () =>\n | PostgresJsDatabase<Record<string, unknown>>\n | undefined {\n return () => drizzleTransactionStorage.getStore()\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["PollingService","EventStatus","failedEvent: FailedBusEvent","error: unknown","AsyncLocalStorage"],"sources":["../src/schema.ts","../src/postgres-drizzle-outbox.ts","../src/transaction-storage.ts"],"sourcesContent":["import {\n integer,\n jsonb,\n pgEnum,\n pgTable,\n text,\n timestamp,\n uuid,\n} from \"drizzle-orm/pg-core\"\n\n\nexport const outboxStatusEnum = pgEnum(\"outbox_status\", [\n \"created\",\n \"active\",\n \"completed\",\n \"failed\",\n])\n\nexport const outboxEvents = pgTable(\"outbox_events\", {\n id: uuid(\"id\").primaryKey(),\n type: text(\"type\").notNull(),\n payload: jsonb(\"payload\").notNull(),\n occurredAt: timestamp(\"occurred_at\").notNull(),\n status: outboxStatusEnum(\"status\").notNull().default(\"created\"),\n retryCount: integer(\"retry_count\").notNull().default(0),\n lastError: text(\"last_error\"),\n nextRetryAt: timestamp(\"next_retry_at\"),\n createdOn: timestamp(\"created_on\").notNull().defaultNow(),\n startedOn: timestamp(\"started_on\"),\n completedOn: timestamp(\"completed_on\"),\n keepAlive: timestamp(\"keep_alive\"),\n expireInSeconds: integer(\"expire_in_seconds\").notNull().default(300),\n})\n\nexport const outboxEventsArchive = pgTable(\"outbox_events_archive\", {\n id: uuid(\"id\").primaryKey(),\n type: text(\"type\").notNull(),\n payload: jsonb(\"payload\").notNull(),\n occurredAt: timestamp(\"occurred_at\").notNull(),\n status: outboxStatusEnum(\"status\").notNull(),\n retryCount: integer(\"retry_count\").notNull(),\n lastError: text(\"last_error\"),\n createdOn: timestamp(\"created_on\").notNull(),\n startedOn: timestamp(\"started_on\"),\n completedOn: timestamp(\"completed_on\").notNull(),\n})\n","import { and, eq, inArray, lt, or, sql } from \"drizzle-orm\"\nimport type { PostgresJsDatabase } from \"drizzle-orm/postgres-js\"\nimport {\n type BusEvent,\n type ErrorHandler,\n EventStatus,\n type FailedBusEvent,\n formatErrorMessage,\n type IOutbox,\n type OutboxConfig,\n PollingService,\n reportEventError,\n} from \"outbox-event-bus\"\nimport { outboxEvents, outboxEventsArchive } from \"./schema\"\n\nexport interface PostgresDrizzleOutboxConfig<TSchema extends Record<string, unknown> = Record<string, unknown>> extends OutboxConfig {\n db: PostgresJsDatabase<TSchema>\n getTransaction?: (() => PostgresJsDatabase<TSchema> | undefined) | undefined\n tables?: {\n outboxEvents: typeof outboxEvents\n outboxEventsArchive: typeof outboxEventsArchive\n }\n}\n\nexport class PostgresDrizzleOutbox<TSchema extends Record<string, unknown> = Record<string, unknown>> implements IOutbox<PostgresJsDatabase<TSchema>> {\n private readonly config: Required<PostgresDrizzleOutboxConfig<TSchema>>\n private readonly poller: PollingService\n\n constructor(config: PostgresDrizzleOutboxConfig<TSchema>) {\n this.config = {\n batchSize: config.batchSize ?? 50,\n pollIntervalMs: config.pollIntervalMs ?? 1000,\n maxRetries: config.maxRetries ?? 5,\n baseBackoffMs: config.baseBackoffMs ?? 1000,\n processingTimeoutMs: config.processingTimeoutMs ?? 30000,\n maxErrorBackoffMs: config.maxErrorBackoffMs ?? 30000,\n db: config.db,\n getTransaction: config.getTransaction,\n tables: config.tables ?? {\n outboxEvents,\n outboxEventsArchive,\n },\n }\n\n this.poller = new PollingService({\n pollIntervalMs: this.config.pollIntervalMs,\n baseBackoffMs: this.config.baseBackoffMs,\n maxErrorBackoffMs: this.config.maxErrorBackoffMs,\n processBatch: (handler) => this.processBatch(handler),\n })\n }\n\n async publish(\n events: BusEvent[],\n transaction?: PostgresJsDatabase<TSchema>\n ): Promise<void> {\n const executor = transaction ?? this.config.getTransaction?.() ?? this.config.db\n\n await executor.insert(this.config.tables.outboxEvents).values(\n events.map((event) => ({\n id: event.id,\n type: event.type,\n payload: event.payload,\n occurredAt: event.occurredAt,\n status: EventStatus.CREATED,\n }))\n )\n }\n\n async getFailedEvents(): Promise<FailedBusEvent[]> {\n const events = await this.config.db\n .select()\n .from(this.config.tables.outboxEvents)\n .where(eq(this.config.tables.outboxEvents.status, EventStatus.FAILED))\n .orderBy(sql`${this.config.tables.outboxEvents.occurredAt} DESC`)\n .limit(100)\n\n return events.map((event) => {\n const failedEvent: FailedBusEvent = {\n id: event.id,\n type: event.type,\n payload: event.payload as any,\n occurredAt: event.occurredAt,\n retryCount: event.retryCount,\n }\n if (event.lastError) failedEvent.error = event.lastError\n if (event.startedOn) failedEvent.lastAttemptAt = event.startedOn\n return failedEvent\n })\n }\n\n async retryEvents(eventIds: string[]): Promise<void> {\n await this.config.db\n .update(this.config.tables.outboxEvents)\n .set({\n status: EventStatus.CREATED,\n retryCount: 0,\n nextRetryAt: null,\n lastError: null,\n })\n .where(inArray(this.config.tables.outboxEvents.id, eventIds))\n }\n\n start(handler: (event: BusEvent) => Promise<void>, onError: ErrorHandler): void {\n this.poller.start(handler, onError)\n }\n\n async stop(): Promise<void> {\n await this.poller.stop()\n }\n\n private async processBatch(handler: (event: BusEvent) => Promise<void>) {\n const now = new Date()\n\n const lockedEvents = await this.config.db.transaction(async (transaction) => {\n const events = await transaction\n .select()\n .from(this.config.tables.outboxEvents)\n .where(\n or(\n eq(this.config.tables.outboxEvents.status, EventStatus.CREATED),\n and(\n eq(this.config.tables.outboxEvents.status, EventStatus.FAILED),\n lt(this.config.tables.outboxEvents.retryCount, this.config.maxRetries),\n lt(this.config.tables.outboxEvents.nextRetryAt, now)\n ),\n and(\n eq(this.config.tables.outboxEvents.status, EventStatus.ACTIVE),\n lt(\n this.config.tables.outboxEvents.keepAlive,\n sql`${now.toISOString()}::timestamp - make_interval(secs => ${this.config.tables.outboxEvents.expireInSeconds})`\n )\n )\n )\n )\n .limit(this.config.batchSize)\n .for(\"update\", { skipLocked: true })\n\n if (events.length === 0) return []\n\n const eventIds = events.map((event) => event.id)\n\n await transaction\n .update(this.config.tables.outboxEvents)\n .set({\n status: EventStatus.ACTIVE,\n startedOn: now,\n keepAlive: now,\n })\n .where(inArray(this.config.tables.outboxEvents.id, eventIds))\n\n return events\n })\n\n if (lockedEvents.length === 0) return\n\n // 2. Process events outside of the transaction\n for (const event of lockedEvents) {\n try {\n await handler(event)\n\n // use the main db connection for individual updates to avoid long transactions\n await this.config.db.transaction(async (transaction) => {\n await transaction.insert(this.config.tables.outboxEventsArchive).values({\n id: event.id,\n type: event.type,\n payload: event.payload as any,\n occurredAt: event.occurredAt,\n status: EventStatus.COMPLETED,\n retryCount: event.retryCount,\n createdOn: event.createdOn,\n startedOn: now,\n completedOn: new Date(),\n })\n await transaction\n .delete(this.config.tables.outboxEvents)\n .where(eq(this.config.tables.outboxEvents.id, event.id))\n })\n } catch (error: unknown) {\n const retryCount = event.retryCount + 1\n reportEventError(this.poller.onError, error, event, retryCount, this.config.maxRetries)\n\n const delay = this.poller.calculateBackoff(retryCount)\n await this.config.db\n .update(this.config.tables.outboxEvents)\n .set({\n status: EventStatus.FAILED,\n retryCount,\n lastError: formatErrorMessage(error),\n nextRetryAt: new Date(Date.now() + delay),\n })\n .where(eq(this.config.tables.outboxEvents.id, event.id))\n }\n }\n }\n}\n","import { AsyncLocalStorage } from \"node:async_hooks\"\nimport type { PostgresJsDatabase } from \"drizzle-orm/postgres-js\"\n\nexport function createDrizzleTransactionStorage<\n TSchema extends Record<string, unknown> = Record<string, unknown>,\n>() {\n const storage = new AsyncLocalStorage<PostgresJsDatabase<TSchema>>()\n\n async function withTransaction<T>(\n db: PostgresJsDatabase<TSchema>,\n fn: (tx: PostgresJsDatabase<TSchema>) => Promise<T>\n ): Promise<T> {\n return db.transaction(async (tx) => {\n return storage.run(tx, () => fn(tx))\n })\n }\n\n function getTransaction(): PostgresJsDatabase<TSchema> | undefined {\n return storage.getStore()\n }\n\n return { storage, withTransaction, getTransaction }\n}\n\n/**\n * @deprecated Use `createDrizzleTransactionStorage()` for type-safe schema support.\n */\nexport const drizzleTransactionStorage = new AsyncLocalStorage<\n PostgresJsDatabase<Record<string, unknown>>\n>()\n\n/**\n * @deprecated Use `createDrizzleTransactionStorage()` for type-safe schema support.\n */\nexport async function withDrizzleTransaction<T>(\n db: PostgresJsDatabase<Record<string, unknown>>,\n fn: (tx: PostgresJsDatabase<Record<string, unknown>>) => Promise<T>\n): Promise<T> {\n return db.transaction(async (tx) => {\n return drizzleTransactionStorage.run(tx, () => fn(tx))\n })\n}\n\n/**\n * @deprecated Use `createDrizzleTransactionStorage()` for type-safe schema support.\n */\nexport function getDrizzleTransaction(): () =>\n | PostgresJsDatabase<Record<string, unknown>>\n | undefined {\n return () => drizzleTransactionStorage.getStore()\n}\n"],"mappings":"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"}
|
package/dist/index.d.cts
CHANGED
|
@@ -454,19 +454,19 @@ declare const outboxEventsArchive: drizzle_orm_pg_core0.PgTableWithColumns<{
|
|
|
454
454
|
}>;
|
|
455
455
|
//#endregion
|
|
456
456
|
//#region src/postgres-drizzle-outbox.d.ts
|
|
457
|
-
interface PostgresDrizzleOutboxConfig extends OutboxConfig {
|
|
458
|
-
db: PostgresJsDatabase<
|
|
459
|
-
getTransaction?: (() => PostgresJsDatabase<
|
|
457
|
+
interface PostgresDrizzleOutboxConfig<TSchema extends Record<string, unknown> = Record<string, unknown>> extends OutboxConfig {
|
|
458
|
+
db: PostgresJsDatabase<TSchema>;
|
|
459
|
+
getTransaction?: (() => PostgresJsDatabase<TSchema> | undefined) | undefined;
|
|
460
460
|
tables?: {
|
|
461
461
|
outboxEvents: typeof outboxEvents;
|
|
462
462
|
outboxEventsArchive: typeof outboxEventsArchive;
|
|
463
463
|
};
|
|
464
464
|
}
|
|
465
|
-
declare class PostgresDrizzleOutbox
|
|
465
|
+
declare class PostgresDrizzleOutbox<TSchema extends Record<string, unknown> = Record<string, unknown>> implements IOutbox<PostgresJsDatabase<TSchema>> {
|
|
466
466
|
private readonly config;
|
|
467
467
|
private readonly poller;
|
|
468
|
-
constructor(config: PostgresDrizzleOutboxConfig);
|
|
469
|
-
publish(events: BusEvent[], transaction?: PostgresJsDatabase<
|
|
468
|
+
constructor(config: PostgresDrizzleOutboxConfig<TSchema>);
|
|
469
|
+
publish(events: BusEvent[], transaction?: PostgresJsDatabase<TSchema>): Promise<void>;
|
|
470
470
|
getFailedEvents(): Promise<FailedBusEvent[]>;
|
|
471
471
|
retryEvents(eventIds: string[]): Promise<void>;
|
|
472
472
|
start(handler: (event: BusEvent) => Promise<void>, onError: ErrorHandler): void;
|
|
@@ -475,9 +475,23 @@ declare class PostgresDrizzleOutbox implements IOutbox<PostgresJsDatabase<Record
|
|
|
475
475
|
}
|
|
476
476
|
//#endregion
|
|
477
477
|
//#region src/transaction-storage.d.ts
|
|
478
|
+
declare function createDrizzleTransactionStorage<TSchema extends Record<string, unknown> = Record<string, unknown>>(): {
|
|
479
|
+
storage: AsyncLocalStorage<PostgresJsDatabase<TSchema>>;
|
|
480
|
+
withTransaction: <T>(db: PostgresJsDatabase<TSchema>, fn: (tx: PostgresJsDatabase<TSchema>) => Promise<T>) => Promise<T>;
|
|
481
|
+
getTransaction: () => PostgresJsDatabase<TSchema> | undefined;
|
|
482
|
+
};
|
|
483
|
+
/**
|
|
484
|
+
* @deprecated Use `createDrizzleTransactionStorage()` for type-safe schema support.
|
|
485
|
+
*/
|
|
478
486
|
declare const drizzleTransactionStorage: AsyncLocalStorage<PostgresJsDatabase<Record<string, unknown>>>;
|
|
487
|
+
/**
|
|
488
|
+
* @deprecated Use `createDrizzleTransactionStorage()` for type-safe schema support.
|
|
489
|
+
*/
|
|
479
490
|
declare function withDrizzleTransaction<T>(db: PostgresJsDatabase<Record<string, unknown>>, fn: (tx: PostgresJsDatabase<Record<string, unknown>>) => Promise<T>): Promise<T>;
|
|
491
|
+
/**
|
|
492
|
+
* @deprecated Use `createDrizzleTransactionStorage()` for type-safe schema support.
|
|
493
|
+
*/
|
|
480
494
|
declare function getDrizzleTransaction(): () => PostgresJsDatabase<Record<string, unknown>> | undefined;
|
|
481
495
|
//#endregion
|
|
482
|
-
export { PostgresDrizzleOutbox, PostgresDrizzleOutboxConfig, drizzleTransactionStorage, getDrizzleTransaction, outboxEvents, outboxEventsArchive, outboxStatusEnum, withDrizzleTransaction };
|
|
496
|
+
export { PostgresDrizzleOutbox, PostgresDrizzleOutboxConfig, createDrizzleTransactionStorage, drizzleTransactionStorage, getDrizzleTransaction, outboxEvents, outboxEventsArchive, outboxStatusEnum, withDrizzleTransaction };
|
|
483
497
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../../../core/src/errors/errors.ts","../../../core/src/types/types.ts","../../../core/src/types/interfaces.ts","../src/schema.ts","../src/postgres-drizzle-outbox.ts","../src/transaction-storage.ts"],"sourcesContent":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../../../core/src/errors/errors.ts","../../../core/src/types/types.ts","../../../core/src/types/interfaces.ts","../src/schema.ts","../src/postgres-drizzle-outbox.ts","../src/transaction-storage.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/index.d.mts
CHANGED
|
@@ -454,19 +454,19 @@ declare const outboxEventsArchive: drizzle_orm_pg_core0.PgTableWithColumns<{
|
|
|
454
454
|
}>;
|
|
455
455
|
//#endregion
|
|
456
456
|
//#region src/postgres-drizzle-outbox.d.ts
|
|
457
|
-
interface PostgresDrizzleOutboxConfig extends OutboxConfig {
|
|
458
|
-
db: PostgresJsDatabase<
|
|
459
|
-
getTransaction?: (() => PostgresJsDatabase<
|
|
457
|
+
interface PostgresDrizzleOutboxConfig<TSchema extends Record<string, unknown> = Record<string, unknown>> extends OutboxConfig {
|
|
458
|
+
db: PostgresJsDatabase<TSchema>;
|
|
459
|
+
getTransaction?: (() => PostgresJsDatabase<TSchema> | undefined) | undefined;
|
|
460
460
|
tables?: {
|
|
461
461
|
outboxEvents: typeof outboxEvents;
|
|
462
462
|
outboxEventsArchive: typeof outboxEventsArchive;
|
|
463
463
|
};
|
|
464
464
|
}
|
|
465
|
-
declare class PostgresDrizzleOutbox
|
|
465
|
+
declare class PostgresDrizzleOutbox<TSchema extends Record<string, unknown> = Record<string, unknown>> implements IOutbox<PostgresJsDatabase<TSchema>> {
|
|
466
466
|
private readonly config;
|
|
467
467
|
private readonly poller;
|
|
468
|
-
constructor(config: PostgresDrizzleOutboxConfig);
|
|
469
|
-
publish(events: BusEvent[], transaction?: PostgresJsDatabase<
|
|
468
|
+
constructor(config: PostgresDrizzleOutboxConfig<TSchema>);
|
|
469
|
+
publish(events: BusEvent[], transaction?: PostgresJsDatabase<TSchema>): Promise<void>;
|
|
470
470
|
getFailedEvents(): Promise<FailedBusEvent[]>;
|
|
471
471
|
retryEvents(eventIds: string[]): Promise<void>;
|
|
472
472
|
start(handler: (event: BusEvent) => Promise<void>, onError: ErrorHandler): void;
|
|
@@ -475,9 +475,23 @@ declare class PostgresDrizzleOutbox implements IOutbox<PostgresJsDatabase<Record
|
|
|
475
475
|
}
|
|
476
476
|
//#endregion
|
|
477
477
|
//#region src/transaction-storage.d.ts
|
|
478
|
+
declare function createDrizzleTransactionStorage<TSchema extends Record<string, unknown> = Record<string, unknown>>(): {
|
|
479
|
+
storage: AsyncLocalStorage<PostgresJsDatabase<TSchema>>;
|
|
480
|
+
withTransaction: <T>(db: PostgresJsDatabase<TSchema>, fn: (tx: PostgresJsDatabase<TSchema>) => Promise<T>) => Promise<T>;
|
|
481
|
+
getTransaction: () => PostgresJsDatabase<TSchema> | undefined;
|
|
482
|
+
};
|
|
483
|
+
/**
|
|
484
|
+
* @deprecated Use `createDrizzleTransactionStorage()` for type-safe schema support.
|
|
485
|
+
*/
|
|
478
486
|
declare const drizzleTransactionStorage: AsyncLocalStorage<PostgresJsDatabase<Record<string, unknown>>>;
|
|
487
|
+
/**
|
|
488
|
+
* @deprecated Use `createDrizzleTransactionStorage()` for type-safe schema support.
|
|
489
|
+
*/
|
|
479
490
|
declare function withDrizzleTransaction<T>(db: PostgresJsDatabase<Record<string, unknown>>, fn: (tx: PostgresJsDatabase<Record<string, unknown>>) => Promise<T>): Promise<T>;
|
|
491
|
+
/**
|
|
492
|
+
* @deprecated Use `createDrizzleTransactionStorage()` for type-safe schema support.
|
|
493
|
+
*/
|
|
480
494
|
declare function getDrizzleTransaction(): () => PostgresJsDatabase<Record<string, unknown>> | undefined;
|
|
481
495
|
//#endregion
|
|
482
|
-
export { PostgresDrizzleOutbox, PostgresDrizzleOutboxConfig, drizzleTransactionStorage, getDrizzleTransaction, outboxEvents, outboxEventsArchive, outboxStatusEnum, withDrizzleTransaction };
|
|
496
|
+
export { PostgresDrizzleOutbox, PostgresDrizzleOutboxConfig, createDrizzleTransactionStorage, drizzleTransactionStorage, getDrizzleTransaction, outboxEvents, outboxEventsArchive, outboxStatusEnum, withDrizzleTransaction };
|
|
483
497
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../../core/src/errors/errors.ts","../../../core/src/types/types.ts","../../../core/src/types/interfaces.ts","../src/schema.ts","../src/postgres-drizzle-outbox.ts","../src/transaction-storage.ts"],"sourcesContent":[],"mappings":";;;;;UAEiB,kBAAA;UACP,WAAW;;;AADrB;AAMsB,uBAAA,WAAW,CAAA,iBACd,kBADc,GACO,kBADP,CAAA,SAEvB,KAAA,CAFuB;EACd,OAAA,CAAA,EAEA,QAFA,GAAA,SAAA;EAAqB,WAAA,CAAA,OAAA,EAAA,MAAA,EAAA,IAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EAIe,QAJf;;;;KCL5B;;QAEJ;EDJS,OAAA,ECKN,CDLM;EAMK,UAAA,ECAR,IDAmB;EACd,QAAA,CAAA,ECAN,MDAM,CAAA,MAAA,EAAA,OAAA,CAAA;CAAqB;AAErB,KCCP,cDDO,CAAA,UAAA,MAAA,GAAA,MAAA,EAAA,IAAA,OAAA,CAAA,GCCkD,QDDlD,CCC2D,CDD3D,ECC8D,CDD9D,CAAA,GAAA;EAEoC,KAAA,CAAA,EAAA,MAAA;EAH7C,UAAA,EAAA,MAAA;EAAK,aAAA,CAAA,ECKG,IDLH;;ACJP,KAuBI,YAAA,GAvBJ,CAAA,KAAA,EAuB2B,WAvB3B,EAAA,GAAA,IAAA;;;UCHS;oBACG,0BAA0B,iBAAiB;2BACpC,aAAa,wBAAwB;EFH/C,IAAA,EAAA,GAAA,GEIH,OFJG,CAAA,IAAkB,CAAA;EAMb,eAAW,EAAA,GAAA,GEDR,OFCQ,CEDA,cFCA,EAAA,CAAA;EACd,WAAA,EAAA,CAAA,QAAA,EAAA,MAAA,EAAA,EAAA,GEDoB,OFCpB,CAAA,IAAA,CAAA;;AEL4C,UA8D9C,YAAA,CA9D8C;EACpC,UAAA,CAAA,EAAA,MAAA;EAAa,aAAA,CAAA,EAAA,MAAA;EAAwB,cAAA,CAAA,EAAA,MAAA;EAClD,SAAA,CAAA,EAAA,MAAA;EACmB,mBAAA,CAAA,EAAA,MAAA;EAAR,iBAAA,CAAA,EAAA,MAAA;;;;cCIZ,kBAKX,oBAAA,CAL2B;cAOhB,mCAAY;;;;IHhBR,EAAA,EG8Bf,oBAAA,CAAA,QH7BmB,CAAA;MAKC,IAAA,EAAW,IAAA;MACd,SAAA,EAAA,eAAA;MAAqB,QAAA,EAAA,QAAA;MAErB,UAAA,EAAA,QAAA;MAEoC,IAAA,EAAA,MAAA;MAH7C,WAAA,EAAA,MAAA;MAAK,OAAA,EAAA,IAAA;;;;MCNH,iBAAQ,EAAA,KAAA;MAEZ,UAAA,EAAA,SAAA;MACG,UAAA,EAAA,KAAA;MACG,QAAA,EAAA,SAAA;MACD,SAAA,EAAA,SAAA;IAAM,CAAA,EAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA;IAGP,IAAA,+BAAc,CAAA;MAAoD,IAAA,EAAA,MAAA;MAAG,SAAA,EAAA,eAAA;MAAZ,QAAA,EAAA,QAAA;MAGnD,UAAA,EAAA,QAAA;MAAI,IAAA,EAAA,MAAA;MAcV,WAAY,EAAA,MAAW;;;;MC1BlB,eAAO,EAAA,KAAA;MACJ,iBAAA,EAAA,KAAA;MAA0B,UAAA,EAAA,CAAA,MAAA,EAAA,GAAA,MAAA,EAAA,CAAA;MAAiB,UAAA,EAAA,KAAA;MACpC,QAAA,EAAA,SAAA;MAAa,SAAA,EAAA,SAAA;IAAwB,CAAA,EAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA;IAClD,OAAA,+BAAA,CAAA;MACmB,IAAA,EAAA,SAAA;MAAR,SAAA,EAAA,eAAA;MACc,QAAA,EAAA,MAAA;MAAO,UAAA,EAAA,SAAA;MA0D7B,IAAA,EAAA,OAAY;;;;MCvDhB,YAKX,EAAA,KAAA;MAEW,eAcX,EAAA,KAAA;MAAA,iBAAA,EAAA,KAAA;;;;;;;;;;;;;;;;;;;gBAduB,EAAA,KAAA;MAAA,QAAA,EAAA,SAAA;MAgBZ,SAAA,EAAA,SAWX;IAAA,CAAA,EAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA;;;;;;;;;;;;;;gBAX8B,EAAA,KAAA;MAAA,QAAA,EAAA,SAAA;;;;MCnBf,IAAA,EAAA,aAAA;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../../core/src/errors/errors.ts","../../../core/src/types/types.ts","../../../core/src/types/interfaces.ts","../src/schema.ts","../src/postgres-drizzle-outbox.ts","../src/transaction-storage.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
|
@@ -148,16 +148,41 @@ var PostgresDrizzleOutbox = class {
|
|
|
148
148
|
|
|
149
149
|
//#endregion
|
|
150
150
|
//#region src/transaction-storage.ts
|
|
151
|
+
function createDrizzleTransactionStorage() {
|
|
152
|
+
const storage = new AsyncLocalStorage();
|
|
153
|
+
async function withTransaction(db, fn) {
|
|
154
|
+
return db.transaction(async (tx) => {
|
|
155
|
+
return storage.run(tx, () => fn(tx));
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
function getTransaction() {
|
|
159
|
+
return storage.getStore();
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
storage,
|
|
163
|
+
withTransaction,
|
|
164
|
+
getTransaction
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* @deprecated Use `createDrizzleTransactionStorage()` for type-safe schema support.
|
|
169
|
+
*/
|
|
151
170
|
const drizzleTransactionStorage = new AsyncLocalStorage();
|
|
171
|
+
/**
|
|
172
|
+
* @deprecated Use `createDrizzleTransactionStorage()` for type-safe schema support.
|
|
173
|
+
*/
|
|
152
174
|
async function withDrizzleTransaction(db, fn) {
|
|
153
175
|
return db.transaction(async (tx) => {
|
|
154
176
|
return drizzleTransactionStorage.run(tx, () => fn(tx));
|
|
155
177
|
});
|
|
156
178
|
}
|
|
179
|
+
/**
|
|
180
|
+
* @deprecated Use `createDrizzleTransactionStorage()` for type-safe schema support.
|
|
181
|
+
*/
|
|
157
182
|
function getDrizzleTransaction() {
|
|
158
183
|
return () => drizzleTransactionStorage.getStore();
|
|
159
184
|
}
|
|
160
185
|
|
|
161
186
|
//#endregion
|
|
162
|
-
export { PostgresDrizzleOutbox, drizzleTransactionStorage, getDrizzleTransaction, outboxEvents, outboxEventsArchive, outboxStatusEnum, withDrizzleTransaction };
|
|
187
|
+
export { PostgresDrizzleOutbox, createDrizzleTransactionStorage, drizzleTransactionStorage, getDrizzleTransaction, outboxEvents, outboxEventsArchive, outboxStatusEnum, withDrizzleTransaction };
|
|
163
188
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["failedEvent: FailedBusEvent","error: unknown"],"sources":["../src/schema.ts","../src/postgres-drizzle-outbox.ts","../src/transaction-storage.ts"],"sourcesContent":["import {\n integer,\n jsonb,\n pgEnum,\n pgTable,\n text,\n timestamp,\n uuid,\n} from \"drizzle-orm/pg-core\"\n\n\nexport const outboxStatusEnum = pgEnum(\"outbox_status\", [\n \"created\",\n \"active\",\n \"completed\",\n \"failed\",\n])\n\nexport const outboxEvents = pgTable(\"outbox_events\", {\n id: uuid(\"id\").primaryKey(),\n type: text(\"type\").notNull(),\n payload: jsonb(\"payload\").notNull(),\n occurredAt: timestamp(\"occurred_at\").notNull(),\n status: outboxStatusEnum(\"status\").notNull().default(\"created\"),\n retryCount: integer(\"retry_count\").notNull().default(0),\n lastError: text(\"last_error\"),\n nextRetryAt: timestamp(\"next_retry_at\"),\n createdOn: timestamp(\"created_on\").notNull().defaultNow(),\n startedOn: timestamp(\"started_on\"),\n completedOn: timestamp(\"completed_on\"),\n keepAlive: timestamp(\"keep_alive\"),\n expireInSeconds: integer(\"expire_in_seconds\").notNull().default(300),\n})\n\nexport const outboxEventsArchive = pgTable(\"outbox_events_archive\", {\n id: uuid(\"id\").primaryKey(),\n type: text(\"type\").notNull(),\n payload: jsonb(\"payload\").notNull(),\n occurredAt: timestamp(\"occurred_at\").notNull(),\n status: outboxStatusEnum(\"status\").notNull(),\n retryCount: integer(\"retry_count\").notNull(),\n lastError: text(\"last_error\"),\n createdOn: timestamp(\"created_on\").notNull(),\n startedOn: timestamp(\"started_on\"),\n completedOn: timestamp(\"completed_on\").notNull(),\n})\n","import { and, eq, inArray, lt, or, sql } from \"drizzle-orm\"\nimport type { PostgresJsDatabase } from \"drizzle-orm/postgres-js\"\nimport {\n type BusEvent,\n type ErrorHandler,\n EventStatus,\n type FailedBusEvent,\n formatErrorMessage,\n type IOutbox,\n type OutboxConfig,\n PollingService,\n reportEventError,\n} from \"outbox-event-bus\"\nimport { outboxEvents, outboxEventsArchive } from \"./schema\"\n\nexport interface PostgresDrizzleOutboxConfig extends OutboxConfig {\n db: PostgresJsDatabase<Record<string, unknown>>\n getTransaction?: (() => PostgresJsDatabase<Record<string, unknown>> | undefined) | undefined\n tables?: {\n outboxEvents: typeof outboxEvents\n outboxEventsArchive: typeof outboxEventsArchive\n }\n}\n\nexport class PostgresDrizzleOutbox implements IOutbox<PostgresJsDatabase<Record<string, unknown>>> {\n private readonly config: Required<PostgresDrizzleOutboxConfig>\n private readonly poller: PollingService\n\n constructor(config: PostgresDrizzleOutboxConfig) {\n this.config = {\n batchSize: config.batchSize ?? 50,\n pollIntervalMs: config.pollIntervalMs ?? 1000,\n maxRetries: config.maxRetries ?? 5,\n baseBackoffMs: config.baseBackoffMs ?? 1000,\n processingTimeoutMs: config.processingTimeoutMs ?? 30000,\n maxErrorBackoffMs: config.maxErrorBackoffMs ?? 30000,\n db: config.db,\n getTransaction: config.getTransaction,\n tables: config.tables ?? {\n outboxEvents,\n outboxEventsArchive,\n },\n }\n\n this.poller = new PollingService({\n pollIntervalMs: this.config.pollIntervalMs,\n baseBackoffMs: this.config.baseBackoffMs,\n maxErrorBackoffMs: this.config.maxErrorBackoffMs,\n processBatch: (handler) => this.processBatch(handler),\n })\n }\n\n async publish(\n events: BusEvent[],\n transaction?: PostgresJsDatabase<Record<string, unknown>>\n ): Promise<void> {\n const executor = transaction ?? this.config.getTransaction?.() ?? this.config.db\n\n await executor.insert(this.config.tables.outboxEvents).values(\n events.map((event) => ({\n id: event.id,\n type: event.type,\n payload: event.payload,\n occurredAt: event.occurredAt,\n status: EventStatus.CREATED,\n }))\n )\n }\n\n async getFailedEvents(): Promise<FailedBusEvent[]> {\n const events = await this.config.db\n .select()\n .from(this.config.tables.outboxEvents)\n .where(eq(this.config.tables.outboxEvents.status, EventStatus.FAILED))\n .orderBy(sql`${this.config.tables.outboxEvents.occurredAt} DESC`)\n .limit(100)\n\n return events.map((event) => {\n const failedEvent: FailedBusEvent = {\n id: event.id,\n type: event.type,\n payload: event.payload as any,\n occurredAt: event.occurredAt,\n retryCount: event.retryCount,\n }\n if (event.lastError) failedEvent.error = event.lastError\n if (event.startedOn) failedEvent.lastAttemptAt = event.startedOn\n return failedEvent\n })\n }\n\n async retryEvents(eventIds: string[]): Promise<void> {\n await this.config.db\n .update(this.config.tables.outboxEvents)\n .set({\n status: EventStatus.CREATED,\n retryCount: 0,\n nextRetryAt: null,\n lastError: null,\n })\n .where(inArray(this.config.tables.outboxEvents.id, eventIds))\n }\n\n start(handler: (event: BusEvent) => Promise<void>, onError: ErrorHandler): void {\n this.poller.start(handler, onError)\n }\n\n async stop(): Promise<void> {\n await this.poller.stop()\n }\n\n private async processBatch(handler: (event: BusEvent) => Promise<void>) {\n const now = new Date()\n\n const lockedEvents = await this.config.db.transaction(async (transaction) => {\n const events = await transaction\n .select()\n .from(this.config.tables.outboxEvents)\n .where(\n or(\n eq(this.config.tables.outboxEvents.status, EventStatus.CREATED),\n and(\n eq(this.config.tables.outboxEvents.status, EventStatus.FAILED),\n lt(this.config.tables.outboxEvents.retryCount, this.config.maxRetries),\n lt(this.config.tables.outboxEvents.nextRetryAt, now)\n ),\n and(\n eq(this.config.tables.outboxEvents.status, EventStatus.ACTIVE),\n lt(\n this.config.tables.outboxEvents.keepAlive,\n sql`${now.toISOString()}::timestamp - make_interval(secs => ${this.config.tables.outboxEvents.expireInSeconds})`\n )\n )\n )\n )\n .limit(this.config.batchSize)\n .for(\"update\", { skipLocked: true })\n\n if (events.length === 0) return []\n\n const eventIds = events.map((event) => event.id)\n\n await transaction\n .update(this.config.tables.outboxEvents)\n .set({\n status: EventStatus.ACTIVE,\n startedOn: now,\n keepAlive: now,\n })\n .where(inArray(this.config.tables.outboxEvents.id, eventIds))\n\n return events\n })\n\n if (lockedEvents.length === 0) return\n\n // 2. Process events outside of the transaction\n for (const event of lockedEvents) {\n try {\n await handler(event)\n\n // use the main db connection for individual updates to avoid long transactions\n await this.config.db.transaction(async (transaction) => {\n await transaction.insert(this.config.tables.outboxEventsArchive).values({\n id: event.id,\n type: event.type,\n payload: event.payload as any,\n occurredAt: event.occurredAt,\n status: EventStatus.COMPLETED,\n retryCount: event.retryCount,\n createdOn: event.createdOn,\n startedOn: now,\n completedOn: new Date(),\n })\n await transaction\n .delete(this.config.tables.outboxEvents)\n .where(eq(this.config.tables.outboxEvents.id, event.id))\n })\n } catch (error: unknown) {\n const retryCount = event.retryCount + 1\n reportEventError(this.poller.onError, error, event, retryCount, this.config.maxRetries)\n\n const delay = this.poller.calculateBackoff(retryCount)\n await this.config.db\n .update(this.config.tables.outboxEvents)\n .set({\n status: EventStatus.FAILED,\n retryCount,\n lastError: formatErrorMessage(error),\n nextRetryAt: new Date(Date.now() + delay),\n })\n .where(eq(this.config.tables.outboxEvents.id, event.id))\n }\n }\n }\n}\n","import { AsyncLocalStorage } from \"node:async_hooks\"\nimport type { PostgresJsDatabase } from \"drizzle-orm/postgres-js\"\n\nexport const drizzleTransactionStorage = new AsyncLocalStorage<\n PostgresJsDatabase<Record<string, unknown>>\n>()\n\nexport async function withDrizzleTransaction<T>(\n db: PostgresJsDatabase<Record<string, unknown>>,\n fn: (tx: PostgresJsDatabase<Record<string, unknown>>) => Promise<T>\n): Promise<T> {\n return db.transaction(async (tx) => {\n return drizzleTransactionStorage.run(tx, () => fn(tx))\n })\n}\n\nexport function getDrizzleTransaction(): () =>\n | PostgresJsDatabase<Record<string, unknown>>\n | undefined {\n return () => drizzleTransactionStorage.getStore()\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["failedEvent: FailedBusEvent","error: unknown"],"sources":["../src/schema.ts","../src/postgres-drizzle-outbox.ts","../src/transaction-storage.ts"],"sourcesContent":["import {\n integer,\n jsonb,\n pgEnum,\n pgTable,\n text,\n timestamp,\n uuid,\n} from \"drizzle-orm/pg-core\"\n\n\nexport const outboxStatusEnum = pgEnum(\"outbox_status\", [\n \"created\",\n \"active\",\n \"completed\",\n \"failed\",\n])\n\nexport const outboxEvents = pgTable(\"outbox_events\", {\n id: uuid(\"id\").primaryKey(),\n type: text(\"type\").notNull(),\n payload: jsonb(\"payload\").notNull(),\n occurredAt: timestamp(\"occurred_at\").notNull(),\n status: outboxStatusEnum(\"status\").notNull().default(\"created\"),\n retryCount: integer(\"retry_count\").notNull().default(0),\n lastError: text(\"last_error\"),\n nextRetryAt: timestamp(\"next_retry_at\"),\n createdOn: timestamp(\"created_on\").notNull().defaultNow(),\n startedOn: timestamp(\"started_on\"),\n completedOn: timestamp(\"completed_on\"),\n keepAlive: timestamp(\"keep_alive\"),\n expireInSeconds: integer(\"expire_in_seconds\").notNull().default(300),\n})\n\nexport const outboxEventsArchive = pgTable(\"outbox_events_archive\", {\n id: uuid(\"id\").primaryKey(),\n type: text(\"type\").notNull(),\n payload: jsonb(\"payload\").notNull(),\n occurredAt: timestamp(\"occurred_at\").notNull(),\n status: outboxStatusEnum(\"status\").notNull(),\n retryCount: integer(\"retry_count\").notNull(),\n lastError: text(\"last_error\"),\n createdOn: timestamp(\"created_on\").notNull(),\n startedOn: timestamp(\"started_on\"),\n completedOn: timestamp(\"completed_on\").notNull(),\n})\n","import { and, eq, inArray, lt, or, sql } from \"drizzle-orm\"\nimport type { PostgresJsDatabase } from \"drizzle-orm/postgres-js\"\nimport {\n type BusEvent,\n type ErrorHandler,\n EventStatus,\n type FailedBusEvent,\n formatErrorMessage,\n type IOutbox,\n type OutboxConfig,\n PollingService,\n reportEventError,\n} from \"outbox-event-bus\"\nimport { outboxEvents, outboxEventsArchive } from \"./schema\"\n\nexport interface PostgresDrizzleOutboxConfig<TSchema extends Record<string, unknown> = Record<string, unknown>> extends OutboxConfig {\n db: PostgresJsDatabase<TSchema>\n getTransaction?: (() => PostgresJsDatabase<TSchema> | undefined) | undefined\n tables?: {\n outboxEvents: typeof outboxEvents\n outboxEventsArchive: typeof outboxEventsArchive\n }\n}\n\nexport class PostgresDrizzleOutbox<TSchema extends Record<string, unknown> = Record<string, unknown>> implements IOutbox<PostgresJsDatabase<TSchema>> {\n private readonly config: Required<PostgresDrizzleOutboxConfig<TSchema>>\n private readonly poller: PollingService\n\n constructor(config: PostgresDrizzleOutboxConfig<TSchema>) {\n this.config = {\n batchSize: config.batchSize ?? 50,\n pollIntervalMs: config.pollIntervalMs ?? 1000,\n maxRetries: config.maxRetries ?? 5,\n baseBackoffMs: config.baseBackoffMs ?? 1000,\n processingTimeoutMs: config.processingTimeoutMs ?? 30000,\n maxErrorBackoffMs: config.maxErrorBackoffMs ?? 30000,\n db: config.db,\n getTransaction: config.getTransaction,\n tables: config.tables ?? {\n outboxEvents,\n outboxEventsArchive,\n },\n }\n\n this.poller = new PollingService({\n pollIntervalMs: this.config.pollIntervalMs,\n baseBackoffMs: this.config.baseBackoffMs,\n maxErrorBackoffMs: this.config.maxErrorBackoffMs,\n processBatch: (handler) => this.processBatch(handler),\n })\n }\n\n async publish(\n events: BusEvent[],\n transaction?: PostgresJsDatabase<TSchema>\n ): Promise<void> {\n const executor = transaction ?? this.config.getTransaction?.() ?? this.config.db\n\n await executor.insert(this.config.tables.outboxEvents).values(\n events.map((event) => ({\n id: event.id,\n type: event.type,\n payload: event.payload,\n occurredAt: event.occurredAt,\n status: EventStatus.CREATED,\n }))\n )\n }\n\n async getFailedEvents(): Promise<FailedBusEvent[]> {\n const events = await this.config.db\n .select()\n .from(this.config.tables.outboxEvents)\n .where(eq(this.config.tables.outboxEvents.status, EventStatus.FAILED))\n .orderBy(sql`${this.config.tables.outboxEvents.occurredAt} DESC`)\n .limit(100)\n\n return events.map((event) => {\n const failedEvent: FailedBusEvent = {\n id: event.id,\n type: event.type,\n payload: event.payload as any,\n occurredAt: event.occurredAt,\n retryCount: event.retryCount,\n }\n if (event.lastError) failedEvent.error = event.lastError\n if (event.startedOn) failedEvent.lastAttemptAt = event.startedOn\n return failedEvent\n })\n }\n\n async retryEvents(eventIds: string[]): Promise<void> {\n await this.config.db\n .update(this.config.tables.outboxEvents)\n .set({\n status: EventStatus.CREATED,\n retryCount: 0,\n nextRetryAt: null,\n lastError: null,\n })\n .where(inArray(this.config.tables.outboxEvents.id, eventIds))\n }\n\n start(handler: (event: BusEvent) => Promise<void>, onError: ErrorHandler): void {\n this.poller.start(handler, onError)\n }\n\n async stop(): Promise<void> {\n await this.poller.stop()\n }\n\n private async processBatch(handler: (event: BusEvent) => Promise<void>) {\n const now = new Date()\n\n const lockedEvents = await this.config.db.transaction(async (transaction) => {\n const events = await transaction\n .select()\n .from(this.config.tables.outboxEvents)\n .where(\n or(\n eq(this.config.tables.outboxEvents.status, EventStatus.CREATED),\n and(\n eq(this.config.tables.outboxEvents.status, EventStatus.FAILED),\n lt(this.config.tables.outboxEvents.retryCount, this.config.maxRetries),\n lt(this.config.tables.outboxEvents.nextRetryAt, now)\n ),\n and(\n eq(this.config.tables.outboxEvents.status, EventStatus.ACTIVE),\n lt(\n this.config.tables.outboxEvents.keepAlive,\n sql`${now.toISOString()}::timestamp - make_interval(secs => ${this.config.tables.outboxEvents.expireInSeconds})`\n )\n )\n )\n )\n .limit(this.config.batchSize)\n .for(\"update\", { skipLocked: true })\n\n if (events.length === 0) return []\n\n const eventIds = events.map((event) => event.id)\n\n await transaction\n .update(this.config.tables.outboxEvents)\n .set({\n status: EventStatus.ACTIVE,\n startedOn: now,\n keepAlive: now,\n })\n .where(inArray(this.config.tables.outboxEvents.id, eventIds))\n\n return events\n })\n\n if (lockedEvents.length === 0) return\n\n // 2. Process events outside of the transaction\n for (const event of lockedEvents) {\n try {\n await handler(event)\n\n // use the main db connection for individual updates to avoid long transactions\n await this.config.db.transaction(async (transaction) => {\n await transaction.insert(this.config.tables.outboxEventsArchive).values({\n id: event.id,\n type: event.type,\n payload: event.payload as any,\n occurredAt: event.occurredAt,\n status: EventStatus.COMPLETED,\n retryCount: event.retryCount,\n createdOn: event.createdOn,\n startedOn: now,\n completedOn: new Date(),\n })\n await transaction\n .delete(this.config.tables.outboxEvents)\n .where(eq(this.config.tables.outboxEvents.id, event.id))\n })\n } catch (error: unknown) {\n const retryCount = event.retryCount + 1\n reportEventError(this.poller.onError, error, event, retryCount, this.config.maxRetries)\n\n const delay = this.poller.calculateBackoff(retryCount)\n await this.config.db\n .update(this.config.tables.outboxEvents)\n .set({\n status: EventStatus.FAILED,\n retryCount,\n lastError: formatErrorMessage(error),\n nextRetryAt: new Date(Date.now() + delay),\n })\n .where(eq(this.config.tables.outboxEvents.id, event.id))\n }\n }\n }\n}\n","import { AsyncLocalStorage } from \"node:async_hooks\"\nimport type { PostgresJsDatabase } from \"drizzle-orm/postgres-js\"\n\nexport function createDrizzleTransactionStorage<\n TSchema extends Record<string, unknown> = Record<string, unknown>,\n>() {\n const storage = new AsyncLocalStorage<PostgresJsDatabase<TSchema>>()\n\n async function withTransaction<T>(\n db: PostgresJsDatabase<TSchema>,\n fn: (tx: PostgresJsDatabase<TSchema>) => Promise<T>\n ): Promise<T> {\n return db.transaction(async (tx) => {\n return storage.run(tx, () => fn(tx))\n })\n }\n\n function getTransaction(): PostgresJsDatabase<TSchema> | undefined {\n return storage.getStore()\n }\n\n return { storage, withTransaction, getTransaction }\n}\n\n/**\n * @deprecated Use `createDrizzleTransactionStorage()` for type-safe schema support.\n */\nexport const drizzleTransactionStorage = new AsyncLocalStorage<\n PostgresJsDatabase<Record<string, unknown>>\n>()\n\n/**\n * @deprecated Use `createDrizzleTransactionStorage()` for type-safe schema support.\n */\nexport async function withDrizzleTransaction<T>(\n db: PostgresJsDatabase<Record<string, unknown>>,\n fn: (tx: PostgresJsDatabase<Record<string, unknown>>) => Promise<T>\n): Promise<T> {\n return db.transaction(async (tx) => {\n return drizzleTransactionStorage.run(tx, () => fn(tx))\n })\n}\n\n/**\n * @deprecated Use `createDrizzleTransactionStorage()` for type-safe schema support.\n */\nexport function getDrizzleTransaction(): () =>\n | PostgresJsDatabase<Record<string, unknown>>\n | undefined {\n return () => drizzleTransactionStorage.getStore()\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -13,20 +13,20 @@ import {
|
|
|
13
13
|
} from "outbox-event-bus"
|
|
14
14
|
import { outboxEvents, outboxEventsArchive } from "./schema"
|
|
15
15
|
|
|
16
|
-
export interface PostgresDrizzleOutboxConfig extends OutboxConfig {
|
|
17
|
-
db: PostgresJsDatabase<
|
|
18
|
-
getTransaction?: (() => PostgresJsDatabase<
|
|
16
|
+
export interface PostgresDrizzleOutboxConfig<TSchema extends Record<string, unknown> = Record<string, unknown>> extends OutboxConfig {
|
|
17
|
+
db: PostgresJsDatabase<TSchema>
|
|
18
|
+
getTransaction?: (() => PostgresJsDatabase<TSchema> | undefined) | undefined
|
|
19
19
|
tables?: {
|
|
20
20
|
outboxEvents: typeof outboxEvents
|
|
21
21
|
outboxEventsArchive: typeof outboxEventsArchive
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
export class PostgresDrizzleOutbox
|
|
26
|
-
private readonly config: Required<PostgresDrizzleOutboxConfig
|
|
25
|
+
export class PostgresDrizzleOutbox<TSchema extends Record<string, unknown> = Record<string, unknown>> implements IOutbox<PostgresJsDatabase<TSchema>> {
|
|
26
|
+
private readonly config: Required<PostgresDrizzleOutboxConfig<TSchema>>
|
|
27
27
|
private readonly poller: PollingService
|
|
28
28
|
|
|
29
|
-
constructor(config: PostgresDrizzleOutboxConfig) {
|
|
29
|
+
constructor(config: PostgresDrizzleOutboxConfig<TSchema>) {
|
|
30
30
|
this.config = {
|
|
31
31
|
batchSize: config.batchSize ?? 50,
|
|
32
32
|
pollIntervalMs: config.pollIntervalMs ?? 1000,
|
|
@@ -52,7 +52,7 @@ export class PostgresDrizzleOutbox implements IOutbox<PostgresJsDatabase<Record<
|
|
|
52
52
|
|
|
53
53
|
async publish(
|
|
54
54
|
events: BusEvent[],
|
|
55
|
-
transaction?: PostgresJsDatabase<
|
|
55
|
+
transaction?: PostgresJsDatabase<TSchema>
|
|
56
56
|
): Promise<void> {
|
|
57
57
|
const executor = transaction ?? this.config.getTransaction?.() ?? this.config.db
|
|
58
58
|
|
|
@@ -1,10 +1,37 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from "node:async_hooks"
|
|
2
2
|
import type { PostgresJsDatabase } from "drizzle-orm/postgres-js"
|
|
3
3
|
|
|
4
|
+
export function createDrizzleTransactionStorage<
|
|
5
|
+
TSchema extends Record<string, unknown> = Record<string, unknown>,
|
|
6
|
+
>() {
|
|
7
|
+
const storage = new AsyncLocalStorage<PostgresJsDatabase<TSchema>>()
|
|
8
|
+
|
|
9
|
+
async function withTransaction<T>(
|
|
10
|
+
db: PostgresJsDatabase<TSchema>,
|
|
11
|
+
fn: (tx: PostgresJsDatabase<TSchema>) => Promise<T>
|
|
12
|
+
): Promise<T> {
|
|
13
|
+
return db.transaction(async (tx) => {
|
|
14
|
+
return storage.run(tx, () => fn(tx))
|
|
15
|
+
})
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function getTransaction(): PostgresJsDatabase<TSchema> | undefined {
|
|
19
|
+
return storage.getStore()
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return { storage, withTransaction, getTransaction }
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @deprecated Use `createDrizzleTransactionStorage()` for type-safe schema support.
|
|
27
|
+
*/
|
|
4
28
|
export const drizzleTransactionStorage = new AsyncLocalStorage<
|
|
5
29
|
PostgresJsDatabase<Record<string, unknown>>
|
|
6
30
|
>()
|
|
7
31
|
|
|
32
|
+
/**
|
|
33
|
+
* @deprecated Use `createDrizzleTransactionStorage()` for type-safe schema support.
|
|
34
|
+
*/
|
|
8
35
|
export async function withDrizzleTransaction<T>(
|
|
9
36
|
db: PostgresJsDatabase<Record<string, unknown>>,
|
|
10
37
|
fn: (tx: PostgresJsDatabase<Record<string, unknown>>) => Promise<T>
|
|
@@ -14,6 +41,9 @@ export async function withDrizzleTransaction<T>(
|
|
|
14
41
|
})
|
|
15
42
|
}
|
|
16
43
|
|
|
44
|
+
/**
|
|
45
|
+
* @deprecated Use `createDrizzleTransactionStorage()` for type-safe schema support.
|
|
46
|
+
*/
|
|
17
47
|
export function getDrizzleTransaction(): () =>
|
|
18
48
|
| PostgresJsDatabase<Record<string, unknown>>
|
|
19
49
|
| undefined {
|