@relaybus/core 0.3.1 → 0.4.1

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/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { D as Duration, E as EventEnvelope, a as DomainEvent, S as StandardSchemaV1, P as PayloadOf, C as ClaimedDelivery, b as EventHeaders, c as EventStoreStatistics, d as ErrorInfo, e as PurgeResult, f as EventStore, T as Transport, g as EventReference, h as Clock, A as AppendEntry, i as AppendResult, j as ClaimRequest, L as LeaseReference, k as DeliveryQuery, l as DeliveryRecord, m as PurgeRequest, n as EventClass } from './transport-BlfzIBZD.cjs';
2
- export { o as AttemptsExhaustedError, p as CloseOptions, q as ConfigurationError, r as DELIVERY_STATUSES, s as DefineEventKeyOptions, t as DefineEventOptions, u as DeliveryStatus, v as DispatcherStoppedError, w as DrainIncompleteError, x as EventKeyFunction, y as EventStoreTransactionOptions, z as EventValidationError, H as HandlerTimeoutError, I as InvalidEnvelopeError, B as InvalidTransportMessage, F as LeaseLostError, G as LifecycleError, M as MAX_TIMER_DELAY_MS, N as NewDelivery, J as NonRetryableError, R as RelayBusError, K as TransactionRequiredError, O as TransactionTimeoutError, Q as TransportMessage, U as TransportMessageHandler, V as TransportSubscriptionHooks, W as ValidationIssue, X as assertEventType, Y as defineEvent, Z as systemClock, _ as toErrorInfo, $ as toMilliseconds, a0 as validatePayload } from './transport-BlfzIBZD.cjs';
1
+ import { D as Duration, E as EventEnvelope, a as DomainEvent, S as StandardSchemaV1, P as PayloadOf, C as ClaimedDelivery, b as EventHeaders, c as EventStoreStatistics, d as ErrorInfo, e as PurgeResult, f as EventStore, T as Transport, g as EventReference, h as Clock, A as AppendEntry, i as AppendResult, j as ClaimRequest, L as LeaseReference, k as DeliveryQuery, l as DeliveryRecord, m as PurgeRequest, n as EventClass } from './transport-DIFdeXQY.cjs';
2
+ export { o as AttemptsExhaustedError, p as CloseOptions, q as ConfigurationError, r as DELIVERY_STATUSES, s as DefineEventKeyOptions, t as DefineEventOptions, u as DeliveryStatus, v as DispatcherStoppedError, w as DrainIncompleteError, x as EventKeyFunction, y as EventStoreTransactionOptions, z as EventValidationError, H as HandlerTimeoutError, I as InvalidEnvelopeError, B as InvalidTransportMessage, F as LeaseLostError, G as LifecycleError, M as MAX_TIMER_DELAY_MS, N as NewDelivery, J as NonRetryableError, R as RelayBusError, K as TransactionRequiredError, O as TransactionTimeoutError, Q as TransportMessage, U as TransportMessageHandler, V as TransportSubscriptionHooks, W as ValidationIssue, X as assertEventType, Y as defineEvent, Z as systemClock, _ as toErrorInfo, $ as toMilliseconds, a0 as validatePayload } from './transport-DIFdeXQY.cjs';
3
3
 
4
4
  /**
5
5
  * How the delay between attempts is randomized.
@@ -965,6 +965,11 @@ declare class RelayBus<TTransaction = unknown> {
965
965
  */
966
966
  drain(maxBatches?: number): Promise<number>;
967
967
  listDeliveries(query?: DeliveryQuery): Promise<DeliveryRecord[]>;
968
+ /**
969
+ * Asks the dispatcher to claim now. Call it right after committing your own transaction that published,
970
+ * when the store cannot report the commit (see Tuning, "Wake-up after your transaction commits").
971
+ */
972
+ wake(): void;
968
973
  /** Moves dead deliveries back to pending with a fresh attempt budget. */
969
974
  requeue(deliveryIds: readonly string[]): Promise<number>;
970
975
  statistics(): Promise<EventStoreStatistics>;
@@ -972,4 +977,5 @@ declare class RelayBus<TTransaction = unknown> {
972
977
  purgeExpired(): Promise<PurgeResult>;
973
978
  }
974
979
 
975
- export { AppendEntry, AppendResult, type BacklogEvent, type Catalog, type CatalogDeclaration, type CatalogDescription, type CatalogEntry, type CatalogEventClass, type CatalogEventName, type CatalogEventSelection, type CatalogEvents, CatalogPublisher, type CatalogRole, type ClaimFinishedEvent, ClaimRequest, ClaimedDelivery, Clock, DEFAULT_RETRY_POLICY, DEFAULT_ROUTE_RETRY_POLICY, type DefineCatalogOptions, type DeliveryKind, DeliveryQuery, DeliveryRecord, type DispatcherOptions, DomainEvent, Duration, ErrorInfo, EventClass, EventEnvelope, type EventHandler, EventHeaders, type EventOf, EventReference, EventStore, EventStoreStatistics, type FailureStage, type HandlerContext, type HandlerDescriptor, type HandlerFinishedEvent, type HandlerShapeOf, type HandlerStartedEvent, type HandlersOf, type IdentifierGenerator, InMemoryEventStore, type InMemoryEventStoreOptions, InMemoryTransaction, type InboundSubscriptionOptions, type InvalidMessageEvent, type JitterStrategy, LeaseReference, type MatchingHandlers, type NoExtraHandlers, type OperationOutcome, type PartialHandlersOf, PayloadOf, type ProcessTraceInput, type PublishFinishedEvent, type PublishOneOptions, type PublishOptions, type PublishTarget, type PublishTraceInput, PurgeRequest, PurgeResult, type ReceiveFinishedEvent, type ReceiveOutcome, type ReceiveStatus, RelayBus, type RelayBusLogger, type RelayBusObserver, type RelayBusOptions, type RelayBusTracer, type RetentionOptions, type RetryPolicy, type RetryPolicyOptions, type RouteOptions, type SendTraceInput, StandardSchemaV1, type StopOptions, type StopResult, type SubscribeCatalogOptions, type SubscribeOptions, TRACEPARENT_HEADER, TRACESTATE_HEADER, type TraceContext, type TransactionMode, Transport, type TransportSentEvent, type UnroutedEventPolicy, computeRetryDelay, consume, createRetryPolicy, createUuidV7, defineCatalog, defineHandlers, describeCatalog, isRetryableError, produce, traceContextOf };
980
+ export { AppendEntry, AppendResult, CatalogPublisher, ClaimRequest, ClaimedDelivery, Clock, DEFAULT_RETRY_POLICY, DEFAULT_ROUTE_RETRY_POLICY, DeliveryQuery, DeliveryRecord, DomainEvent, Duration, ErrorInfo, EventClass, EventEnvelope, EventHeaders, EventReference, EventStore, EventStoreStatistics, InMemoryEventStore, InMemoryTransaction, LeaseReference, PayloadOf, PurgeRequest, PurgeResult, RelayBus, StandardSchemaV1, TRACEPARENT_HEADER, TRACESTATE_HEADER, Transport, computeRetryDelay, consume, createRetryPolicy, createUuidV7, defineCatalog, defineHandlers, describeCatalog, isRetryableError, produce, traceContextOf };
981
+ export type { BacklogEvent, Catalog, CatalogDeclaration, CatalogDescription, CatalogEntry, CatalogEventClass, CatalogEventName, CatalogEventSelection, CatalogEvents, CatalogRole, ClaimFinishedEvent, DefineCatalogOptions, DeliveryKind, DispatcherOptions, EventHandler, EventOf, FailureStage, HandlerContext, HandlerDescriptor, HandlerFinishedEvent, HandlerShapeOf, HandlerStartedEvent, HandlersOf, IdentifierGenerator, InMemoryEventStoreOptions, InboundSubscriptionOptions, InvalidMessageEvent, JitterStrategy, MatchingHandlers, NoExtraHandlers, OperationOutcome, PartialHandlersOf, ProcessTraceInput, PublishFinishedEvent, PublishOneOptions, PublishOptions, PublishTarget, PublishTraceInput, ReceiveFinishedEvent, ReceiveOutcome, ReceiveStatus, RelayBusLogger, RelayBusObserver, RelayBusOptions, RelayBusTracer, RetentionOptions, RetryPolicy, RetryPolicyOptions, RouteOptions, SendTraceInput, StopOptions, StopResult, SubscribeCatalogOptions, SubscribeOptions, TraceContext, TransactionMode, TransportSentEvent, UnroutedEventPolicy };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { D as Duration, E as EventEnvelope, a as DomainEvent, S as StandardSchemaV1, P as PayloadOf, C as ClaimedDelivery, b as EventHeaders, c as EventStoreStatistics, d as ErrorInfo, e as PurgeResult, f as EventStore, T as Transport, g as EventReference, h as Clock, A as AppendEntry, i as AppendResult, j as ClaimRequest, L as LeaseReference, k as DeliveryQuery, l as DeliveryRecord, m as PurgeRequest, n as EventClass } from './transport-BlfzIBZD.js';
2
- export { o as AttemptsExhaustedError, p as CloseOptions, q as ConfigurationError, r as DELIVERY_STATUSES, s as DefineEventKeyOptions, t as DefineEventOptions, u as DeliveryStatus, v as DispatcherStoppedError, w as DrainIncompleteError, x as EventKeyFunction, y as EventStoreTransactionOptions, z as EventValidationError, H as HandlerTimeoutError, I as InvalidEnvelopeError, B as InvalidTransportMessage, F as LeaseLostError, G as LifecycleError, M as MAX_TIMER_DELAY_MS, N as NewDelivery, J as NonRetryableError, R as RelayBusError, K as TransactionRequiredError, O as TransactionTimeoutError, Q as TransportMessage, U as TransportMessageHandler, V as TransportSubscriptionHooks, W as ValidationIssue, X as assertEventType, Y as defineEvent, Z as systemClock, _ as toErrorInfo, $ as toMilliseconds, a0 as validatePayload } from './transport-BlfzIBZD.js';
1
+ import { D as Duration, E as EventEnvelope, a as DomainEvent, S as StandardSchemaV1, P as PayloadOf, C as ClaimedDelivery, b as EventHeaders, c as EventStoreStatistics, d as ErrorInfo, e as PurgeResult, f as EventStore, T as Transport, g as EventReference, h as Clock, A as AppendEntry, i as AppendResult, j as ClaimRequest, L as LeaseReference, k as DeliveryQuery, l as DeliveryRecord, m as PurgeRequest, n as EventClass } from './transport-DIFdeXQY.js';
2
+ export { o as AttemptsExhaustedError, p as CloseOptions, q as ConfigurationError, r as DELIVERY_STATUSES, s as DefineEventKeyOptions, t as DefineEventOptions, u as DeliveryStatus, v as DispatcherStoppedError, w as DrainIncompleteError, x as EventKeyFunction, y as EventStoreTransactionOptions, z as EventValidationError, H as HandlerTimeoutError, I as InvalidEnvelopeError, B as InvalidTransportMessage, F as LeaseLostError, G as LifecycleError, M as MAX_TIMER_DELAY_MS, N as NewDelivery, J as NonRetryableError, R as RelayBusError, K as TransactionRequiredError, O as TransactionTimeoutError, Q as TransportMessage, U as TransportMessageHandler, V as TransportSubscriptionHooks, W as ValidationIssue, X as assertEventType, Y as defineEvent, Z as systemClock, _ as toErrorInfo, $ as toMilliseconds, a0 as validatePayload } from './transport-DIFdeXQY.js';
3
3
 
4
4
  /**
5
5
  * How the delay between attempts is randomized.
@@ -965,6 +965,11 @@ declare class RelayBus<TTransaction = unknown> {
965
965
  */
966
966
  drain(maxBatches?: number): Promise<number>;
967
967
  listDeliveries(query?: DeliveryQuery): Promise<DeliveryRecord[]>;
968
+ /**
969
+ * Asks the dispatcher to claim now. Call it right after committing your own transaction that published,
970
+ * when the store cannot report the commit (see Tuning, "Wake-up after your transaction commits").
971
+ */
972
+ wake(): void;
968
973
  /** Moves dead deliveries back to pending with a fresh attempt budget. */
969
974
  requeue(deliveryIds: readonly string[]): Promise<number>;
970
975
  statistics(): Promise<EventStoreStatistics>;
@@ -972,4 +977,5 @@ declare class RelayBus<TTransaction = unknown> {
972
977
  purgeExpired(): Promise<PurgeResult>;
973
978
  }
974
979
 
975
- export { AppendEntry, AppendResult, type BacklogEvent, type Catalog, type CatalogDeclaration, type CatalogDescription, type CatalogEntry, type CatalogEventClass, type CatalogEventName, type CatalogEventSelection, type CatalogEvents, CatalogPublisher, type CatalogRole, type ClaimFinishedEvent, ClaimRequest, ClaimedDelivery, Clock, DEFAULT_RETRY_POLICY, DEFAULT_ROUTE_RETRY_POLICY, type DefineCatalogOptions, type DeliveryKind, DeliveryQuery, DeliveryRecord, type DispatcherOptions, DomainEvent, Duration, ErrorInfo, EventClass, EventEnvelope, type EventHandler, EventHeaders, type EventOf, EventReference, EventStore, EventStoreStatistics, type FailureStage, type HandlerContext, type HandlerDescriptor, type HandlerFinishedEvent, type HandlerShapeOf, type HandlerStartedEvent, type HandlersOf, type IdentifierGenerator, InMemoryEventStore, type InMemoryEventStoreOptions, InMemoryTransaction, type InboundSubscriptionOptions, type InvalidMessageEvent, type JitterStrategy, LeaseReference, type MatchingHandlers, type NoExtraHandlers, type OperationOutcome, type PartialHandlersOf, PayloadOf, type ProcessTraceInput, type PublishFinishedEvent, type PublishOneOptions, type PublishOptions, type PublishTarget, type PublishTraceInput, PurgeRequest, PurgeResult, type ReceiveFinishedEvent, type ReceiveOutcome, type ReceiveStatus, RelayBus, type RelayBusLogger, type RelayBusObserver, type RelayBusOptions, type RelayBusTracer, type RetentionOptions, type RetryPolicy, type RetryPolicyOptions, type RouteOptions, type SendTraceInput, StandardSchemaV1, type StopOptions, type StopResult, type SubscribeCatalogOptions, type SubscribeOptions, TRACEPARENT_HEADER, TRACESTATE_HEADER, type TraceContext, type TransactionMode, Transport, type TransportSentEvent, type UnroutedEventPolicy, computeRetryDelay, consume, createRetryPolicy, createUuidV7, defineCatalog, defineHandlers, describeCatalog, isRetryableError, produce, traceContextOf };
980
+ export { AppendEntry, AppendResult, CatalogPublisher, ClaimRequest, ClaimedDelivery, Clock, DEFAULT_RETRY_POLICY, DEFAULT_ROUTE_RETRY_POLICY, DeliveryQuery, DeliveryRecord, DomainEvent, Duration, ErrorInfo, EventClass, EventEnvelope, EventHeaders, EventReference, EventStore, EventStoreStatistics, InMemoryEventStore, InMemoryTransaction, LeaseReference, PayloadOf, PurgeRequest, PurgeResult, RelayBus, StandardSchemaV1, TRACEPARENT_HEADER, TRACESTATE_HEADER, Transport, computeRetryDelay, consume, createRetryPolicy, createUuidV7, defineCatalog, defineHandlers, describeCatalog, isRetryableError, produce, traceContextOf };
981
+ export type { BacklogEvent, Catalog, CatalogDeclaration, CatalogDescription, CatalogEntry, CatalogEventClass, CatalogEventName, CatalogEventSelection, CatalogEvents, CatalogRole, ClaimFinishedEvent, DefineCatalogOptions, DeliveryKind, DispatcherOptions, EventHandler, EventOf, FailureStage, HandlerContext, HandlerDescriptor, HandlerFinishedEvent, HandlerShapeOf, HandlerStartedEvent, HandlersOf, IdentifierGenerator, InMemoryEventStoreOptions, InboundSubscriptionOptions, InvalidMessageEvent, JitterStrategy, MatchingHandlers, NoExtraHandlers, OperationOutcome, PartialHandlersOf, ProcessTraceInput, PublishFinishedEvent, PublishOneOptions, PublishOptions, PublishTarget, PublishTraceInput, ReceiveFinishedEvent, ReceiveOutcome, ReceiveStatus, RelayBusLogger, RelayBusObserver, RelayBusOptions, RelayBusTracer, RetentionOptions, RetryPolicy, RetryPolicyOptions, RouteOptions, SendTraceInput, StopOptions, StopResult, SubscribeCatalogOptions, SubscribeOptions, TraceContext, TransactionMode, TransportSentEvent, UnroutedEventPolicy };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { ConfigurationError, assertEventType, CompositeKey, Milliseconds, NonRetryableError, DrainIncompleteError, LifecycleError, schedule, toErrorInfo, LeaseSettlement, TransactionTimeoutError, PositiveInteger, DispatcherStoppedError, DeliveryLeaseIdentity, LeaseLostError, AttemptsExhaustedError, validatePayload, HandlerTimeoutError, TransactionRequiredError, keyFromDefinition, InvalidEnvelopeError } from './chunk-NOR5JHVN.js';
1
+ import { ConfigurationError, assertEventType, CompositeKey, Milliseconds, NonRetryableError, DrainIncompleteError, LifecycleError, toErrorInfo, LeaseSettlement, schedule, TransactionTimeoutError, PositiveInteger, DispatcherStoppedError, DeliveryLeaseIdentity, LeaseLostError, AttemptsExhaustedError, validatePayload, HandlerTimeoutError, TransactionRequiredError, keyFromDefinition, InvalidEnvelopeError } from './chunk-NOR5JHVN.js';
2
2
  export { AttemptsExhaustedError, ConfigurationError, DispatcherStoppedError, DrainIncompleteError, EventValidationError, HandlerTimeoutError, InvalidEnvelopeError, LeaseLostError, LifecycleError, MAX_TIMER_DELAY_MS, NonRetryableError, RelayBusError, TransactionRequiredError, TransactionTimeoutError, assertEventType, defineEvent, toErrorInfo, toMilliseconds, validatePayload } from './chunk-NOR5JHVN.js';
3
3
  import { randomBytes } from 'crypto';
4
4
  import { AsyncLocalStorage } from 'async_hooks';
@@ -2992,7 +2992,7 @@ var EventPublisher = class {
2992
2992
  context,
2993
2993
  delayMs
2994
2994
  }) {
2995
- const result = await this.#appendInTransaction(entries, context);
2995
+ const { result, committed } = await this.#appendInTransaction(entries, context);
2996
2996
  const appended = new Set(result.appendedEventIds);
2997
2997
  const published = entries.map((entry) => entry.event).filter((envelope) => appended.has(envelope.id));
2998
2998
  if (published.length > 0) {
@@ -3001,22 +3001,26 @@ var EventPublisher = class {
3001
3001
  deliveries: result.appendedDeliveryCount
3002
3002
  });
3003
3003
  if (delayMs === 0) {
3004
- this.#parts.scheduleWake();
3004
+ this.#parts.scheduleWake(committed);
3005
3005
  }
3006
3006
  }
3007
3007
  }
3008
+ /** Appends in the caller's transaction, else in one of the store's; `committed` tells which. */
3008
3009
  async #appendInTransaction(entries, { options, scope, now }) {
3009
3010
  const { store, transactionMode, transactionResolver } = this.#parts;
3010
3011
  const transaction = options.transaction ?? scope?.transaction ?? transactionResolver?.();
3011
3012
  if (transaction !== void 0) {
3012
- return store.append(transaction, entries, now);
3013
+ return { result: await store.append(transaction, entries, now), committed: false };
3013
3014
  }
3014
3015
  if (transactionMode === "required") {
3015
3016
  throw new TransactionRequiredError(
3016
3017
  "publish found no transaction. Pass { transaction }, publish inside bus.transaction(), configure transactionResolver, or set transactionMode to optional"
3017
3018
  );
3018
3019
  }
3019
- return store.transaction((ownTransaction) => store.append(ownTransaction, entries, now));
3020
+ const result = await store.transaction(
3021
+ (ownTransaction) => store.append(ownTransaction, entries, now)
3022
+ );
3023
+ return { result, committed: true };
3020
3024
  }
3021
3025
  async #createEnvelope(input) {
3022
3026
  const { event, options, id, scope, now, correlationId } = input;
@@ -3113,7 +3117,7 @@ var EventReceiver = class {
3113
3117
  const status = result.duplicateEventIds.length > 0 ? "duplicate" : "accepted";
3114
3118
  notifier.notify("onReceived", { envelope: normalized, status });
3115
3119
  if (result.appendedDeliveryCount > 0) {
3116
- scheduleWake();
3120
+ scheduleWake(true);
3117
3121
  }
3118
3122
  return status;
3119
3123
  }
@@ -3203,6 +3207,58 @@ function createInboxAndOutbox(core, hooks) {
3203
3207
  };
3204
3208
  }
3205
3209
 
3210
+ // src/bus/publish-wake-ups.ts
3211
+ var FIRST_WAKE_MS = 25;
3212
+ var SECOND_WAKE_MS = 100;
3213
+ var LAST_WAKE_MS = 250;
3214
+ var WAKE_DELAYS_MS = [FIRST_WAKE_MS, SECOND_WAKE_MS, LAST_WAKE_MS];
3215
+ var PublishWakeUps = class {
3216
+ #dependencies;
3217
+ #lastPublishAt = 0;
3218
+ #cancel;
3219
+ /** When the pending timer fires. */
3220
+ #dueAt = 0;
3221
+ constructor(dependencies) {
3222
+ this.#dependencies = dependencies;
3223
+ }
3224
+ /**
3225
+ * Wakes the dispatcher for a publish: at once when its transaction has `committed` (one of relaybus'
3226
+ * own), else at the wake-ups after it.
3227
+ */
3228
+ afterPublish(committed) {
3229
+ if (committed) {
3230
+ this.#dependencies.wake();
3231
+ return;
3232
+ }
3233
+ this.#lastPublishAt = this.#dependencies.clock.now().getTime();
3234
+ if (this.#cancel === void 0 || this.#dueAt > this.#lastPublishAt + FIRST_WAKE_MS) {
3235
+ this.cancel();
3236
+ this.#cancel = this.#arm(FIRST_WAKE_MS);
3237
+ }
3238
+ }
3239
+ cancel() {
3240
+ this.#cancel?.();
3241
+ this.#cancel = void 0;
3242
+ }
3243
+ #fire() {
3244
+ this.#cancel = void 0;
3245
+ this.#dependencies.wake();
3246
+ const elapsed = this.#dependencies.clock.now().getTime() - this.#lastPublishAt;
3247
+ const next = WAKE_DELAYS_MS.find((delay) => delay > elapsed);
3248
+ if (next !== void 0) {
3249
+ this.#cancel = this.#arm(next - elapsed);
3250
+ }
3251
+ }
3252
+ #arm(delayMs) {
3253
+ this.#dueAt = this.#dependencies.clock.now().getTime() + delayMs;
3254
+ return schedule(this.#dependencies.clock, {
3255
+ run: () => this.#fire(),
3256
+ delayMs,
3257
+ unref: true
3258
+ });
3259
+ }
3260
+ };
3261
+
3206
3262
  // src/transaction-budget.ts
3207
3263
  async function runBudgetedTransaction(store, { clock, timeoutMs, work }) {
3208
3264
  const startedAt = clock.now().getTime();
@@ -3235,20 +3291,24 @@ function createTimeoutError(timeoutMs, cause) {
3235
3291
 
3236
3292
  // src/relay-bus.ts
3237
3293
  var DEFAULT_DRAIN_BATCHES = 1e3;
3238
- var WAKE_DELAY_MS = 25;
3239
3294
  var RelayBus = class {
3240
3295
  #parts;
3241
3296
  #lifecycle;
3297
+ #wakeUps;
3242
3298
  constructor(options) {
3243
3299
  this.#parts = assembleRelayBus(options, {
3244
3300
  reportUnrouted: (envelope) => this.#reportUnrouted(envelope),
3245
- scheduleWake: () => this.#scheduleWake(),
3301
+ scheduleWake: (committed) => this.#scheduleWake(committed),
3246
3302
  statistics: () => this.statistics()
3247
3303
  });
3248
3304
  this.#lifecycle = new BusLifecycle({
3249
3305
  ...this.#parts,
3250
3306
  closeTransports: (deadline) => this.#closeTransports(deadline)
3251
3307
  });
3308
+ this.#wakeUps = new PublishWakeUps({
3309
+ clock: this.#parts.clock,
3310
+ wake: () => this.#parts.dispatcher.wake()
3311
+ });
3252
3312
  }
3253
3313
  get store() {
3254
3314
  return this.#parts.store;
@@ -3375,6 +3435,7 @@ var RelayBus = class {
3375
3435
  if (!first) {
3376
3436
  return stopping;
3377
3437
  }
3438
+ this.#wakeUps.cancel();
3378
3439
  const result = await stopping;
3379
3440
  if (!result.graceful) {
3380
3441
  this.#parts.logger.warn(
@@ -3408,6 +3469,13 @@ var RelayBus = class {
3408
3469
  listDeliveries(query = {}) {
3409
3470
  return this.#parts.store.listDeliveries(query);
3410
3471
  }
3472
+ /**
3473
+ * Asks the dispatcher to claim now. Call it right after committing your own transaction that published,
3474
+ * when the store cannot report the commit (see Tuning, "Wake-up after your transaction commits").
3475
+ */
3476
+ wake() {
3477
+ this.#parts.dispatcher.wake();
3478
+ }
3411
3479
  /** Moves dead deliveries back to pending with a fresh attempt budget. */
3412
3480
  async requeue(deliveryIds) {
3413
3481
  const moved = await this.#parts.store.requeue(deliveryIds, this.#parts.clock.now());
@@ -3479,15 +3547,11 @@ var RelayBus = class {
3479
3547
  const routes = registrations.filter((registration) => registration.forwardsToTransport).length;
3480
3548
  return { handlers: registrations.length - routes, routes };
3481
3549
  }
3482
- #scheduleWake() {
3550
+ #scheduleWake(committed) {
3483
3551
  if (this.#lifecycle.state !== "running" || this.#parts.dispatcher.watchesNewDeliveries) {
3484
3552
  return;
3485
3553
  }
3486
- schedule(this.#parts.clock, {
3487
- run: () => this.#parts.dispatcher.wake(),
3488
- delayMs: WAKE_DELAY_MS,
3489
- unref: true
3490
- });
3554
+ this.#wakeUps.afterPublish(committed);
3491
3555
  }
3492
3556
  /** Closes every transport, each at most until the deadline; past it they are asked to force. */
3493
3557
  async #closeTransports(deadline) {