@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/README.md +7 -1
- package/dist/index.cjs +77 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -3
- package/dist/index.d.ts +9 -3
- package/dist/index.js +78 -14
- package/dist/index.js.map +1 -1
- package/dist/internal/index.cjs +306 -43
- package/dist/internal/index.cjs.map +1 -1
- package/dist/internal/index.d.cts +75 -9
- package/dist/internal/index.d.ts +75 -9
- package/dist/internal/index.js +306 -43
- package/dist/internal/index.js.map +1 -1
- package/dist/{transport-BlfzIBZD.d.cts → transport-DIFdeXQY.d.cts} +2 -1
- package/dist/{transport-BlfzIBZD.d.ts → transport-DIFdeXQY.d.ts} +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -311,7 +311,12 @@ deploy, are still claimed and sent by the new route; the store rows keep their o
|
|
|
311
311
|
## Operations
|
|
312
312
|
|
|
313
313
|
`listDeliveries(query)`, `requeue(ids)`, `statistics()`, `purgeExpired()`,
|
|
314
|
-
`handlers()`, `runOnce()` and `drain()` (tests), `start()` and `
|
|
314
|
+
`handlers()`, `runOnce()` and `drain()` (tests), `start()`, `stop()` and `wake()`.
|
|
315
|
+
|
|
316
|
+
**`wake()` after your own commit.** A publish in relaybus' own transaction wakes the dispatcher right after its
|
|
317
|
+
commit. A publish in your transaction commits at a time the bus cannot see: unless the store reports the commit
|
|
318
|
+
(PostgreSQL with `LISTEN/NOTIFY`), the dispatcher is woken 25, 100 and 250 ms after the latest publish and otherwise
|
|
319
|
+
finds the delivery at its next poll. Call `bus.wake()` right after such a commit to claim at once.
|
|
315
320
|
|
|
316
321
|
**`stop({ timeout })` is bounded.** The whole shutdown (stop claiming, wait for running
|
|
317
322
|
handlers, hand back leases, close transports and the store) takes at most `timeout`, default
|
|
@@ -389,6 +394,7 @@ never renamed or reused once released, so branch on them in alerts and retry rul
|
|
|
389
394
|
| `RELAYBUS_RABBITMQ_UNROUTABLE_MESSAGE` | `UnroutableMessageError` | `@relaybus/rabbitmq` |
|
|
390
395
|
| `RELAYBUS_RABBITMQ_MALFORMED_MESSAGE` | `MalformedMessageError` | `@relaybus/rabbitmq` |
|
|
391
396
|
| `RELAYBUS_RABBITMQ_UNSERIALIZABLE_PAYLOAD` | `UnserializablePayloadError` | `@relaybus/rabbitmq` |
|
|
397
|
+
| `RELAYBUS_TESTING_CODEC_CONTRACT` | `CodecContractError` | `@relaybus/testing` |
|
|
392
398
|
| `RELAYBUS_RABBITMQ_UNENCODABLE_EVENT` | `RabbitMqUnencodableEventError` | `@relaybus/rabbitmq` |
|
|
393
399
|
| `RELAYBUS_RABBITMQ_AMQP_LIMIT_EXCEEDED` | `AmqpLimitExceededError` | `@relaybus/rabbitmq` |
|
|
394
400
|
|
package/dist/index.cjs
CHANGED
|
@@ -2993,7 +2993,7 @@ var EventPublisher = class {
|
|
|
2993
2993
|
context,
|
|
2994
2994
|
delayMs
|
|
2995
2995
|
}) {
|
|
2996
|
-
const result = await this.#appendInTransaction(entries, context);
|
|
2996
|
+
const { result, committed } = await this.#appendInTransaction(entries, context);
|
|
2997
2997
|
const appended = new Set(result.appendedEventIds);
|
|
2998
2998
|
const published = entries.map((entry) => entry.event).filter((envelope) => appended.has(envelope.id));
|
|
2999
2999
|
if (published.length > 0) {
|
|
@@ -3002,22 +3002,26 @@ var EventPublisher = class {
|
|
|
3002
3002
|
deliveries: result.appendedDeliveryCount
|
|
3003
3003
|
});
|
|
3004
3004
|
if (delayMs === 0) {
|
|
3005
|
-
this.#parts.scheduleWake();
|
|
3005
|
+
this.#parts.scheduleWake(committed);
|
|
3006
3006
|
}
|
|
3007
3007
|
}
|
|
3008
3008
|
}
|
|
3009
|
+
/** Appends in the caller's transaction, else in one of the store's; `committed` tells which. */
|
|
3009
3010
|
async #appendInTransaction(entries, { options, scope, now }) {
|
|
3010
3011
|
const { store, transactionMode, transactionResolver } = this.#parts;
|
|
3011
3012
|
const transaction = options.transaction ?? scope?.transaction ?? transactionResolver?.();
|
|
3012
3013
|
if (transaction !== void 0) {
|
|
3013
|
-
return store.append(transaction, entries, now);
|
|
3014
|
+
return { result: await store.append(transaction, entries, now), committed: false };
|
|
3014
3015
|
}
|
|
3015
3016
|
if (transactionMode === "required") {
|
|
3016
3017
|
throw new chunkJ76M7XTS_cjs.TransactionRequiredError(
|
|
3017
3018
|
"publish found no transaction. Pass { transaction }, publish inside bus.transaction(), configure transactionResolver, or set transactionMode to optional"
|
|
3018
3019
|
);
|
|
3019
3020
|
}
|
|
3020
|
-
|
|
3021
|
+
const result = await store.transaction(
|
|
3022
|
+
(ownTransaction) => store.append(ownTransaction, entries, now)
|
|
3023
|
+
);
|
|
3024
|
+
return { result, committed: true };
|
|
3021
3025
|
}
|
|
3022
3026
|
async #createEnvelope(input) {
|
|
3023
3027
|
const { event, options, id, scope, now, correlationId } = input;
|
|
@@ -3114,7 +3118,7 @@ var EventReceiver = class {
|
|
|
3114
3118
|
const status = result.duplicateEventIds.length > 0 ? "duplicate" : "accepted";
|
|
3115
3119
|
notifier.notify("onReceived", { envelope: normalized, status });
|
|
3116
3120
|
if (result.appendedDeliveryCount > 0) {
|
|
3117
|
-
scheduleWake();
|
|
3121
|
+
scheduleWake(true);
|
|
3118
3122
|
}
|
|
3119
3123
|
return status;
|
|
3120
3124
|
}
|
|
@@ -3204,6 +3208,58 @@ function createInboxAndOutbox(core, hooks) {
|
|
|
3204
3208
|
};
|
|
3205
3209
|
}
|
|
3206
3210
|
|
|
3211
|
+
// src/bus/publish-wake-ups.ts
|
|
3212
|
+
var FIRST_WAKE_MS = 25;
|
|
3213
|
+
var SECOND_WAKE_MS = 100;
|
|
3214
|
+
var LAST_WAKE_MS = 250;
|
|
3215
|
+
var WAKE_DELAYS_MS = [FIRST_WAKE_MS, SECOND_WAKE_MS, LAST_WAKE_MS];
|
|
3216
|
+
var PublishWakeUps = class {
|
|
3217
|
+
#dependencies;
|
|
3218
|
+
#lastPublishAt = 0;
|
|
3219
|
+
#cancel;
|
|
3220
|
+
/** When the pending timer fires. */
|
|
3221
|
+
#dueAt = 0;
|
|
3222
|
+
constructor(dependencies) {
|
|
3223
|
+
this.#dependencies = dependencies;
|
|
3224
|
+
}
|
|
3225
|
+
/**
|
|
3226
|
+
* Wakes the dispatcher for a publish: at once when its transaction has `committed` (one of relaybus'
|
|
3227
|
+
* own), else at the wake-ups after it.
|
|
3228
|
+
*/
|
|
3229
|
+
afterPublish(committed) {
|
|
3230
|
+
if (committed) {
|
|
3231
|
+
this.#dependencies.wake();
|
|
3232
|
+
return;
|
|
3233
|
+
}
|
|
3234
|
+
this.#lastPublishAt = this.#dependencies.clock.now().getTime();
|
|
3235
|
+
if (this.#cancel === void 0 || this.#dueAt > this.#lastPublishAt + FIRST_WAKE_MS) {
|
|
3236
|
+
this.cancel();
|
|
3237
|
+
this.#cancel = this.#arm(FIRST_WAKE_MS);
|
|
3238
|
+
}
|
|
3239
|
+
}
|
|
3240
|
+
cancel() {
|
|
3241
|
+
this.#cancel?.();
|
|
3242
|
+
this.#cancel = void 0;
|
|
3243
|
+
}
|
|
3244
|
+
#fire() {
|
|
3245
|
+
this.#cancel = void 0;
|
|
3246
|
+
this.#dependencies.wake();
|
|
3247
|
+
const elapsed = this.#dependencies.clock.now().getTime() - this.#lastPublishAt;
|
|
3248
|
+
const next = WAKE_DELAYS_MS.find((delay) => delay > elapsed);
|
|
3249
|
+
if (next !== void 0) {
|
|
3250
|
+
this.#cancel = this.#arm(next - elapsed);
|
|
3251
|
+
}
|
|
3252
|
+
}
|
|
3253
|
+
#arm(delayMs) {
|
|
3254
|
+
this.#dueAt = this.#dependencies.clock.now().getTime() + delayMs;
|
|
3255
|
+
return chunkJ76M7XTS_cjs.schedule(this.#dependencies.clock, {
|
|
3256
|
+
run: () => this.#fire(),
|
|
3257
|
+
delayMs,
|
|
3258
|
+
unref: true
|
|
3259
|
+
});
|
|
3260
|
+
}
|
|
3261
|
+
};
|
|
3262
|
+
|
|
3207
3263
|
// src/transaction-budget.ts
|
|
3208
3264
|
async function runBudgetedTransaction(store, { clock, timeoutMs, work }) {
|
|
3209
3265
|
const startedAt = clock.now().getTime();
|
|
@@ -3236,20 +3292,24 @@ function createTimeoutError(timeoutMs, cause) {
|
|
|
3236
3292
|
|
|
3237
3293
|
// src/relay-bus.ts
|
|
3238
3294
|
var DEFAULT_DRAIN_BATCHES = 1e3;
|
|
3239
|
-
var WAKE_DELAY_MS = 25;
|
|
3240
3295
|
var RelayBus = class {
|
|
3241
3296
|
#parts;
|
|
3242
3297
|
#lifecycle;
|
|
3298
|
+
#wakeUps;
|
|
3243
3299
|
constructor(options) {
|
|
3244
3300
|
this.#parts = assembleRelayBus(options, {
|
|
3245
3301
|
reportUnrouted: (envelope) => this.#reportUnrouted(envelope),
|
|
3246
|
-
scheduleWake: () => this.#scheduleWake(),
|
|
3302
|
+
scheduleWake: (committed) => this.#scheduleWake(committed),
|
|
3247
3303
|
statistics: () => this.statistics()
|
|
3248
3304
|
});
|
|
3249
3305
|
this.#lifecycle = new BusLifecycle({
|
|
3250
3306
|
...this.#parts,
|
|
3251
3307
|
closeTransports: (deadline) => this.#closeTransports(deadline)
|
|
3252
3308
|
});
|
|
3309
|
+
this.#wakeUps = new PublishWakeUps({
|
|
3310
|
+
clock: this.#parts.clock,
|
|
3311
|
+
wake: () => this.#parts.dispatcher.wake()
|
|
3312
|
+
});
|
|
3253
3313
|
}
|
|
3254
3314
|
get store() {
|
|
3255
3315
|
return this.#parts.store;
|
|
@@ -3376,6 +3436,7 @@ var RelayBus = class {
|
|
|
3376
3436
|
if (!first) {
|
|
3377
3437
|
return stopping;
|
|
3378
3438
|
}
|
|
3439
|
+
this.#wakeUps.cancel();
|
|
3379
3440
|
const result = await stopping;
|
|
3380
3441
|
if (!result.graceful) {
|
|
3381
3442
|
this.#parts.logger.warn(
|
|
@@ -3409,6 +3470,13 @@ var RelayBus = class {
|
|
|
3409
3470
|
listDeliveries(query = {}) {
|
|
3410
3471
|
return this.#parts.store.listDeliveries(query);
|
|
3411
3472
|
}
|
|
3473
|
+
/**
|
|
3474
|
+
* Asks the dispatcher to claim now. Call it right after committing your own transaction that published,
|
|
3475
|
+
* when the store cannot report the commit (see Tuning, "Wake-up after your transaction commits").
|
|
3476
|
+
*/
|
|
3477
|
+
wake() {
|
|
3478
|
+
this.#parts.dispatcher.wake();
|
|
3479
|
+
}
|
|
3412
3480
|
/** Moves dead deliveries back to pending with a fresh attempt budget. */
|
|
3413
3481
|
async requeue(deliveryIds) {
|
|
3414
3482
|
const moved = await this.#parts.store.requeue(deliveryIds, this.#parts.clock.now());
|
|
@@ -3480,15 +3548,11 @@ var RelayBus = class {
|
|
|
3480
3548
|
const routes = registrations.filter((registration) => registration.forwardsToTransport).length;
|
|
3481
3549
|
return { handlers: registrations.length - routes, routes };
|
|
3482
3550
|
}
|
|
3483
|
-
#scheduleWake() {
|
|
3551
|
+
#scheduleWake(committed) {
|
|
3484
3552
|
if (this.#lifecycle.state !== "running" || this.#parts.dispatcher.watchesNewDeliveries) {
|
|
3485
3553
|
return;
|
|
3486
3554
|
}
|
|
3487
|
-
|
|
3488
|
-
run: () => this.#parts.dispatcher.wake(),
|
|
3489
|
-
delayMs: WAKE_DELAY_MS,
|
|
3490
|
-
unref: true
|
|
3491
|
-
});
|
|
3555
|
+
this.#wakeUps.afterPublish(committed);
|
|
3492
3556
|
}
|
|
3493
3557
|
/** Closes every transport, each at most until the deadline; past it they are asked to force. */
|
|
3494
3558
|
async #closeTransports(deadline) {
|