cross-tab-worker-databus 0.20.57 → 0.20.59
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/CHANGELOG.md +17 -2
- package/dist/centrifuge.js +1 -1
- package/dist/{chunk-WAQJT3EE.js → chunk-RAUX7RZC.js} +54 -15
- package/dist/chunk-RAUX7RZC.js.map +7 -0
- package/dist/cjs/centrifuge.cjs +53 -14
- package/dist/cjs/centrifuge.cjs.map +2 -2
- package/dist/cjs/index.cjs +53 -14
- package/dist/cjs/index.cjs.map +2 -2
- package/dist/core/cluster.d.ts +13 -0
- package/dist/core/cluster.d.ts.map +1 -1
- package/dist/core/data-bus.d.ts +13 -0
- package/dist/core/data-bus.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/docs/roadmap.md +19 -1
- package/docs/zh/roadmap.md +19 -1
- package/package.json +1 -1
- package/dist/chunk-WAQJT3EE.js.map +0 -7
package/dist/cjs/index.cjs
CHANGED
|
@@ -378,6 +378,18 @@ var WorkerClusterRuntime = class {
|
|
|
378
378
|
// (or local self-subscribe), never via the reverse cache.
|
|
379
379
|
assignedTopics = /* @__PURE__ */ new Map();
|
|
380
380
|
routeOwnerCache = /* @__PURE__ */ new Map();
|
|
381
|
+
routeOwnerCacheMax;
|
|
382
|
+
routeOwnerCacheHits = 0;
|
|
383
|
+
routeOwnerCacheMisses = 0;
|
|
384
|
+
touchRouteOwnerCache(topicKey, value) {
|
|
385
|
+
if (this.routeOwnerCache.has(topicKey)) this.routeOwnerCache.delete(topicKey);
|
|
386
|
+
this.routeOwnerCache.set(topicKey, value);
|
|
387
|
+
while (this.routeOwnerCache.size > this.routeOwnerCacheMax) {
|
|
388
|
+
const oldest = this.routeOwnerCache.keys().next().value;
|
|
389
|
+
if (oldest === void 0) break;
|
|
390
|
+
this.routeOwnerCache.delete(oldest);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
381
393
|
wildcardPublishCache = /* @__PURE__ */ new Map();
|
|
382
394
|
// Reverse mapping: opaque topicKey → plaintext topic. A bounded cache with
|
|
383
395
|
// FIFO eviction — NOT authoritative. It can hold a topicKey that is also in
|
|
@@ -396,6 +408,7 @@ var WorkerClusterRuntime = class {
|
|
|
396
408
|
this.handlers = options.handlers;
|
|
397
409
|
this.maxActiveWorkers = options.maxActiveWorkers ?? DEFAULT_MAX_ACTIVE_WORKERS;
|
|
398
410
|
this.heartbeatIntervalMs = options.heartbeatIntervalMs ?? DEFAULT_HEARTBEAT_INTERVAL_MS;
|
|
411
|
+
this.routeOwnerCacheMax = options.routeOwnerCacheMax ?? 256;
|
|
399
412
|
this.workerTtlMs = options.workerTtlMs ?? DEFAULT_WORKER_TTL_MS;
|
|
400
413
|
const clusterHash = createOpaqueKey(options.clusterKey || "__default__");
|
|
401
414
|
const prefix = options.storagePrefix ?? DEFAULT_STORAGE_PREFIX;
|
|
@@ -588,25 +601,26 @@ var WorkerClusterRuntime = class {
|
|
|
588
601
|
return this.sendControl(this.workerId, "PUBLISH", topic, topicKey, data, metadata);
|
|
589
602
|
}
|
|
590
603
|
const cachedPattern = this.wildcardPublishCache.get(topic);
|
|
591
|
-
if (cachedPattern !== void 0) {
|
|
592
|
-
|
|
593
|
-
return this.sendControl(this.workerId, "PUBLISH", topic, topicKey, data, metadata);
|
|
594
|
-
}
|
|
595
|
-
this.wildcardPublishCache.delete(topic);
|
|
604
|
+
if (cachedPattern !== void 0 && cachedPattern !== null && this.assignedTopics.has(cachedPattern)) {
|
|
605
|
+
return this.sendControl(this.workerId, "PUBLISH", topic, topicKey, data, metadata);
|
|
596
606
|
}
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
607
|
+
if (cachedPattern === void 0) {
|
|
608
|
+
for (const pattern of this.assignedTopics.values()) {
|
|
609
|
+
if (pattern !== topic && topicMatchesPattern(pattern, topic)) {
|
|
610
|
+
this.wildcardPublishCache.set(topic, pattern);
|
|
611
|
+
return this.sendControl(this.workerId, "PUBLISH", topic, topicKey, data, metadata);
|
|
612
|
+
}
|
|
601
613
|
}
|
|
614
|
+
this.wildcardPublishCache.set(topic, null);
|
|
602
615
|
}
|
|
603
|
-
this.wildcardPublishCache.set(topic, null);
|
|
604
616
|
const workers = this.readWorkers();
|
|
605
617
|
const route = this.readRoute(topicKey);
|
|
606
618
|
const cached = this.routeOwnerCache.get(topicKey);
|
|
607
619
|
const cachedLive = cached && route && route.generation === cached.generation && route.workerId === cached.workerId && workers.some((worker) => worker.workerId === cached.workerId);
|
|
620
|
+
if (cachedLive) this.routeOwnerCacheHits += 1;
|
|
621
|
+
else this.routeOwnerCacheMisses += 1;
|
|
608
622
|
const target = cachedLive ? cached.workerId : this.routeOwnerIsLive(route, workers) ? route?.workerId ?? this.workerId : this.workerId;
|
|
609
|
-
if (route && target === route.workerId) this.
|
|
623
|
+
if (route && target === route.workerId) this.touchRouteOwnerCache(topicKey, { workerId: route.workerId, generation: route.generation });
|
|
610
624
|
else this.routeOwnerCache.delete(topicKey);
|
|
611
625
|
return this.sendControl(target, "PUBLISH", topic, topicKey, data, metadata);
|
|
612
626
|
}
|
|
@@ -663,7 +677,8 @@ var WorkerClusterRuntime = class {
|
|
|
663
677
|
routes,
|
|
664
678
|
subscribedTopics: Array.from(this.subscribedTopics),
|
|
665
679
|
assignedTopics: Array.from(this.assignedTopics.values()),
|
|
666
|
-
knownTopics: Array.from(this.knownTopics.entries(), ([topicKey, topic]) => ({ topicKey, topic }))
|
|
680
|
+
knownTopics: Array.from(this.knownTopics.entries(), ([topicKey, topic]) => ({ topicKey, topic })),
|
|
681
|
+
routeOwnerCache: { size: this.routeOwnerCache.size, max: this.routeOwnerCacheMax, hits: this.routeOwnerCacheHits, misses: this.routeOwnerCacheMisses }
|
|
667
682
|
};
|
|
668
683
|
}
|
|
669
684
|
handlePageHide = () => this.pause();
|
|
@@ -1342,6 +1357,13 @@ var CrossTabDataBus = class {
|
|
|
1342
1357
|
// a transport reopen succeeds so traces can correlate repeated failures.
|
|
1343
1358
|
recoveryAttempt = 0;
|
|
1344
1359
|
recoveryExhausted = false;
|
|
1360
|
+
/** Monotonic generation incremented on every successful transport open.
|
|
1361
|
+
* Stays in lockstep with `lastSuccessAt` so callers can detect that the
|
|
1362
|
+
* transport has been reopened even if the timestamp window is short. */
|
|
1363
|
+
recoveryGeneration = 0;
|
|
1364
|
+
/** Timestamp of the most recent successful transport open. Null until the
|
|
1365
|
+
* transport has reached the `ready` state at least once. */
|
|
1366
|
+
lastSuccessAt = null;
|
|
1345
1367
|
// True while the tab is hidden so an in-flight transport start does not mark
|
|
1346
1368
|
// the transport ready after suspendTransport() has stopped it.
|
|
1347
1369
|
suspended = false;
|
|
@@ -1535,7 +1557,11 @@ var CrossTabDataBus = class {
|
|
|
1535
1557
|
if (this.status === "error") {
|
|
1536
1558
|
throw new Error("Transport failed during startup.");
|
|
1537
1559
|
}
|
|
1538
|
-
if (!this.suspended && !this.stopping)
|
|
1560
|
+
if (!this.suspended && !this.stopping) {
|
|
1561
|
+
this.recoveryGeneration += 1;
|
|
1562
|
+
this.lastSuccessAt = this.now();
|
|
1563
|
+
this.transportReady = true;
|
|
1564
|
+
}
|
|
1539
1565
|
});
|
|
1540
1566
|
}).catch((error) => {
|
|
1541
1567
|
if (stopClusterOnFailure) this.started = false;
|
|
@@ -1705,9 +1731,22 @@ var CrossTabDataBus = class {
|
|
|
1705
1731
|
return this.status;
|
|
1706
1732
|
}
|
|
1707
1733
|
/** Return the current automatic transport recovery state. `hasError` means a transport error is currently retained. */
|
|
1734
|
+
/** Return the current automatic transport recovery state plus diagnostics.
|
|
1735
|
+
* `generation` increments on every successful transport open (initial start
|
|
1736
|
+
* and every recovery); `lastSuccessAt` is the timestamp of the most recent
|
|
1737
|
+
* successful open, or `null` until the transport reaches `ready`. */
|
|
1708
1738
|
getRecoveryStats() {
|
|
1709
1739
|
const errorMessage = this.lastError instanceof Error ? this.lastError.message : this.lastError === null ? null : String(this.lastError);
|
|
1710
|
-
return {
|
|
1740
|
+
return {
|
|
1741
|
+
attempt: this.recoveryAttempt,
|
|
1742
|
+
exhausted: this.recoveryExhausted,
|
|
1743
|
+
maxAttempts: this.recoveryMaxAttempts,
|
|
1744
|
+
hasError: this.lastError !== null,
|
|
1745
|
+
errorMessage,
|
|
1746
|
+
errorAt: this.lastErrorAt,
|
|
1747
|
+
generation: this.recoveryGeneration,
|
|
1748
|
+
lastSuccessAt: this.lastSuccessAt
|
|
1749
|
+
};
|
|
1711
1750
|
}
|
|
1712
1751
|
/** Snapshot of the cluster state (workers, routes, assignments).
|
|
1713
1752
|
* For diagnostics only — the returned object is a shallow copy but
|