Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7663f502fa | |||
| 104cd417d8 | |||
| 93254d5d3d | |||
| 9a3f121a9c |
14
changelog.md
14
changelog.md
@@ -1,5 +1,19 @@
|
||||
# Changelog
|
||||
|
||||
## 2026-03-24 - 11.10.4 - fix(monitoring)
|
||||
handle multiple protocol cache entries per backend in metrics output
|
||||
|
||||
- Group detected protocol cache entries by backend host and port so multiple domain-specific records are preserved.
|
||||
- Emit one backend metrics row per cached domain and avoid dropping unmatched protocol cache entries by tracking seen entries with a composite host:port:domain key.
|
||||
- Use cached protocol values when available while keeping backend-only rows for metrics without protocol cache data.
|
||||
|
||||
## 2026-03-23 - 11.10.3 - fix(deps)
|
||||
bump tstest, smartmetrics, and taskbuffer to latest patch releases
|
||||
|
||||
- update @git.zone/tstest from ^3.5.0 to ^3.5.1
|
||||
- update @push.rocks/smartmetrics from ^3.0.2 to ^3.0.3
|
||||
- update @push.rocks/taskbuffer from ^8.0.0 to ^8.0.2
|
||||
|
||||
## 2026-03-23 - 11.10.2 - fix(deps)
|
||||
bump @api.global/typedserver to ^8.4.6 and @push.rocks/smartproxy to ^26.2.1
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@serve.zone/dcrouter",
|
||||
"private": false,
|
||||
"version": "11.10.2",
|
||||
"version": "11.10.4",
|
||||
"description": "A multifaceted routing service handling mail and SMS delivery functions.",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
@@ -25,7 +25,7 @@
|
||||
"@git.zone/tsbuild": "^4.3.0",
|
||||
"@git.zone/tsbundle": "^2.9.1",
|
||||
"@git.zone/tsrun": "^2.0.1",
|
||||
"@git.zone/tstest": "^3.5.0",
|
||||
"@git.zone/tstest": "^3.5.1",
|
||||
"@git.zone/tswatch": "^3.3.0",
|
||||
"@types/node": "^25.5.0"
|
||||
},
|
||||
@@ -47,7 +47,7 @@
|
||||
"@push.rocks/smartguard": "^3.1.0",
|
||||
"@push.rocks/smartjwt": "^2.2.1",
|
||||
"@push.rocks/smartlog": "^3.2.1",
|
||||
"@push.rocks/smartmetrics": "^3.0.2",
|
||||
"@push.rocks/smartmetrics": "^3.0.3",
|
||||
"@push.rocks/smartmongo": "^5.1.0",
|
||||
"@push.rocks/smartmta": "^5.3.1",
|
||||
"@push.rocks/smartnetwork": "^4.4.0",
|
||||
@@ -59,7 +59,7 @@
|
||||
"@push.rocks/smartrx": "^3.0.10",
|
||||
"@push.rocks/smartstate": "^2.2.0",
|
||||
"@push.rocks/smartunique": "^3.0.9",
|
||||
"@push.rocks/taskbuffer": "^8.0.0",
|
||||
"@push.rocks/taskbuffer": "^8.0.2",
|
||||
"@serve.zone/catalog": "^2.9.0",
|
||||
"@serve.zone/interfaces": "^5.3.0",
|
||||
"@serve.zone/remoteingress": "^4.14.1",
|
||||
|
||||
32
pnpm-lock.yaml
generated
32
pnpm-lock.yaml
generated
@@ -60,8 +60,8 @@ importers:
|
||||
specifier: ^3.2.1
|
||||
version: 3.2.1
|
||||
'@push.rocks/smartmetrics':
|
||||
specifier: ^3.0.2
|
||||
version: 3.0.2
|
||||
specifier: ^3.0.3
|
||||
version: 3.0.3
|
||||
'@push.rocks/smartmongo':
|
||||
specifier: ^5.1.0
|
||||
version: 5.1.0(socks@2.8.7)
|
||||
@@ -96,8 +96,8 @@ importers:
|
||||
specifier: ^3.0.9
|
||||
version: 3.0.9
|
||||
'@push.rocks/taskbuffer':
|
||||
specifier: ^8.0.0
|
||||
version: 8.0.0
|
||||
specifier: ^8.0.2
|
||||
version: 8.0.2
|
||||
'@serve.zone/catalog':
|
||||
specifier: ^2.9.0
|
||||
version: 2.9.0(@tiptap/pm@2.27.2)
|
||||
@@ -127,8 +127,8 @@ importers:
|
||||
specifier: ^2.0.1
|
||||
version: 2.0.1
|
||||
'@git.zone/tstest':
|
||||
specifier: ^3.5.0
|
||||
version: 3.5.0(socks@2.8.7)(typescript@5.9.3)
|
||||
specifier: ^3.5.1
|
||||
version: 3.5.1(socks@2.8.7)(typescript@5.9.3)
|
||||
'@git.zone/tswatch':
|
||||
specifier: ^3.3.0
|
||||
version: 3.3.0(@tiptap/pm@2.27.2)
|
||||
@@ -557,8 +557,8 @@ packages:
|
||||
resolution: {integrity: sha512-NEcnsjvlC1o3Z6SS3VhKCf6Ev+Sh4EAinmggslrIR/ppMrvjDbXNFXoyr3PB+GLeSAR0JRZ1fGvVYjpEzjBdIg==}
|
||||
hasBin: true
|
||||
|
||||
'@git.zone/tstest@3.5.0':
|
||||
resolution: {integrity: sha512-ugIJzdVkbgqSSw08SZajE7TB01GIYjEAmIy67O5skhvOyszGifwzJdR+8dS1VbQGlUUWQZMGQ2IowllHbAZYJQ==}
|
||||
'@git.zone/tstest@3.5.1':
|
||||
resolution: {integrity: sha512-R1T3Tr9zun0B5bFq8qK8/KZ2uqHZHfDPB3/mhoL5ekwxGSI4InX5sXMpbNuhw2EdNZ7rMAHNCyeSLz2PwFmNZw==}
|
||||
hasBin: true
|
||||
|
||||
'@git.zone/tswatch@3.3.0':
|
||||
@@ -1205,8 +1205,8 @@ packages:
|
||||
'@push.rocks/smartmatch@2.0.0':
|
||||
resolution: {integrity: sha512-MBzP++1yNIBeox71X6VxpIgZ8m4bXnJpZJ4nWVH6IWpmO38MXTu4X0QF8tQnyT4LFcwvc9iiWaD15cstHa7Mmw==}
|
||||
|
||||
'@push.rocks/smartmetrics@3.0.2':
|
||||
resolution: {integrity: sha512-bW60TrdCubsZwsYK1+lE9y+OoXN8MfB7bhSASlTKtwhExdCbjXYXnSt9W7zerD7HbsUNOsvejIjX9q4oju+P2g==}
|
||||
'@push.rocks/smartmetrics@3.0.3':
|
||||
resolution: {integrity: sha512-RYY4NOla3kraZYVF9TBHgIz4/hSkqVDVNP7tLwhLK5mGBPBy8I/9NWXX6txZKQw6QihP85YD8mWUuUu2xS4D6Q==}
|
||||
|
||||
'@push.rocks/smartmime@1.0.6':
|
||||
resolution: {integrity: sha512-PHd+I4UcsnOATNg8wjDsSAmmJ4CwQFrQCNzd0HSJMs4ZpiK3Ya91almd6GLpDPU370U4HFh4FaPF4eEAI6vkJQ==}
|
||||
@@ -1351,8 +1351,8 @@ packages:
|
||||
'@push.rocks/taskbuffer@6.1.2':
|
||||
resolution: {integrity: sha512-sdqKd8N/GidztQ1k3r8A86rLvD8Afyir5FjYCNJXDD9837JLoqzHaOKGltUSBsCGh2gjsZn6GydsY6HhXQgvZQ==}
|
||||
|
||||
'@push.rocks/taskbuffer@8.0.0':
|
||||
resolution: {integrity: sha512-ay4iXz0JmvsCQCmh5vvuu6KAl8FEZm5EpDXMQbeU+563d89xn+vMhh4+PtwxrVCogMEULWgGnavDYPTuzWtJOA==}
|
||||
'@push.rocks/taskbuffer@8.0.2':
|
||||
resolution: {integrity: sha512-SRCAzrSHysW5XEjwZ494V60ybdpOo/s96jDD3sn7SkYolzg2Pboh+SW5Q7SVNcdkP4b9wCEizOYe9CB3vj3W6w==}
|
||||
|
||||
'@push.rocks/webrequest@4.0.5':
|
||||
resolution: {integrity: sha512-wVSCaXqJ9Vh+rbwVz0wDl46dYz4rnwwSrm5vbVXKbuH6oKTPF0YRoujeJPqRltIn64RVGdLeY9/6ix+ZCrzhsg==}
|
||||
@@ -4387,7 +4387,7 @@ snapshots:
|
||||
'@push.rocks/smartstream': 3.4.0
|
||||
'@push.rocks/smarttime': 4.2.3
|
||||
'@push.rocks/smartwatch': 6.4.0
|
||||
'@push.rocks/taskbuffer': 8.0.0
|
||||
'@push.rocks/taskbuffer': 8.0.2
|
||||
'@push.rocks/webrequest': 4.0.5
|
||||
'@push.rocks/webstore': 2.0.20
|
||||
'@tsclass/tsclass': 9.5.0
|
||||
@@ -5171,7 +5171,7 @@ snapshots:
|
||||
'@push.rocks/smartshell': 3.3.8
|
||||
tsx: 4.21.0
|
||||
|
||||
'@git.zone/tstest@3.5.0(socks@2.8.7)(typescript@5.9.3)':
|
||||
'@git.zone/tstest@3.5.1(socks@2.8.7)(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@git.zone/tsbundle': 2.9.1
|
||||
'@git.zone/tsrun': 2.0.1
|
||||
@@ -6384,7 +6384,7 @@ snapshots:
|
||||
dependencies:
|
||||
matcher: 5.0.0
|
||||
|
||||
'@push.rocks/smartmetrics@3.0.2':
|
||||
'@push.rocks/smartmetrics@3.0.3':
|
||||
dependencies:
|
||||
'@push.rocks/smartdelay': 3.0.5
|
||||
'@push.rocks/smartlog': 3.2.1
|
||||
@@ -6807,7 +6807,7 @@ snapshots:
|
||||
- supports-color
|
||||
- vue
|
||||
|
||||
'@push.rocks/taskbuffer@8.0.0':
|
||||
'@push.rocks/taskbuffer@8.0.2':
|
||||
dependencies:
|
||||
'@design.estate/dees-element': 2.2.3
|
||||
'@push.rocks/lik': 6.4.0
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@serve.zone/dcrouter',
|
||||
version: '11.10.2',
|
||||
version: '11.10.4',
|
||||
description: 'A multifaceted routing service handling mail and SMS delivery functions.'
|
||||
}
|
||||
|
||||
@@ -595,47 +595,84 @@ export class MetricsManager {
|
||||
const backendMetrics = proxyMetrics.backends.byBackend();
|
||||
const protocolCache = proxyMetrics.backends.detectedProtocols();
|
||||
|
||||
// Index protocol cache by "host:port"
|
||||
const cacheByKey = new Map<string, (typeof protocolCache)[number]>();
|
||||
// Group protocol cache entries by host:port so we can match them to backend metrics.
|
||||
// The protocol cache is keyed by (host, port, domain) in Rust, so the same host:port
|
||||
// can have multiple entries for different domains.
|
||||
const cacheByBackend = new Map<string, (typeof protocolCache)[number][]>();
|
||||
for (const entry of protocolCache) {
|
||||
cacheByKey.set(`${entry.host}:${entry.port}`, entry);
|
||||
const backendKey = `${entry.host}:${entry.port}`;
|
||||
let entries = cacheByBackend.get(backendKey);
|
||||
if (!entries) {
|
||||
entries = [];
|
||||
cacheByBackend.set(backendKey, entries);
|
||||
}
|
||||
entries.push(entry);
|
||||
}
|
||||
|
||||
const backends: Array<any> = [];
|
||||
const seen = new Set<string>();
|
||||
const seenCacheKeys = new Set<string>();
|
||||
|
||||
for (const [key, bm] of backendMetrics) {
|
||||
seen.add(key);
|
||||
const cache = cacheByKey.get(key);
|
||||
backends.push({
|
||||
backend: key,
|
||||
domain: cache?.domain ?? null,
|
||||
protocol: bm.protocol,
|
||||
activeConnections: bm.activeConnections,
|
||||
totalConnections: bm.totalConnections,
|
||||
connectErrors: bm.connectErrors,
|
||||
handshakeErrors: bm.handshakeErrors,
|
||||
requestErrors: bm.requestErrors,
|
||||
avgConnectTimeMs: Math.round(bm.avgConnectTimeMs * 10) / 10,
|
||||
poolHitRate: Math.round(bm.poolHitRate * 1000) / 1000,
|
||||
h2Failures: bm.h2Failures,
|
||||
h2Suppressed: cache?.h2Suppressed ?? false,
|
||||
h3Suppressed: cache?.h3Suppressed ?? false,
|
||||
h2CooldownRemainingSecs: cache?.h2CooldownRemainingSecs ?? null,
|
||||
h3CooldownRemainingSecs: cache?.h3CooldownRemainingSecs ?? null,
|
||||
h2ConsecutiveFailures: cache?.h2ConsecutiveFailures ?? null,
|
||||
h3ConsecutiveFailures: cache?.h3ConsecutiveFailures ?? null,
|
||||
h3Port: cache?.h3Port ?? null,
|
||||
cacheAgeSecs: cache?.ageSecs ?? null,
|
||||
});
|
||||
const cacheEntries = cacheByBackend.get(key);
|
||||
if (!cacheEntries || cacheEntries.length === 0) {
|
||||
// No protocol cache entry — emit one row with backend metrics only
|
||||
backends.push({
|
||||
backend: key,
|
||||
domain: null,
|
||||
protocol: bm.protocol,
|
||||
activeConnections: bm.activeConnections,
|
||||
totalConnections: bm.totalConnections,
|
||||
connectErrors: bm.connectErrors,
|
||||
handshakeErrors: bm.handshakeErrors,
|
||||
requestErrors: bm.requestErrors,
|
||||
avgConnectTimeMs: Math.round(bm.avgConnectTimeMs * 10) / 10,
|
||||
poolHitRate: Math.round(bm.poolHitRate * 1000) / 1000,
|
||||
h2Failures: bm.h2Failures,
|
||||
h2Suppressed: false,
|
||||
h3Suppressed: false,
|
||||
h2CooldownRemainingSecs: null,
|
||||
h3CooldownRemainingSecs: null,
|
||||
h2ConsecutiveFailures: null,
|
||||
h3ConsecutiveFailures: null,
|
||||
h3Port: null,
|
||||
cacheAgeSecs: null,
|
||||
});
|
||||
} else {
|
||||
// One row per domain, each enriched with the shared backend metrics
|
||||
for (const cache of cacheEntries) {
|
||||
const compositeKey = `${cache.host}:${cache.port}:${cache.domain ?? ''}`;
|
||||
seenCacheKeys.add(compositeKey);
|
||||
backends.push({
|
||||
backend: key,
|
||||
domain: cache.domain ?? null,
|
||||
protocol: cache.protocol ?? bm.protocol,
|
||||
activeConnections: bm.activeConnections,
|
||||
totalConnections: bm.totalConnections,
|
||||
connectErrors: bm.connectErrors,
|
||||
handshakeErrors: bm.handshakeErrors,
|
||||
requestErrors: bm.requestErrors,
|
||||
avgConnectTimeMs: Math.round(bm.avgConnectTimeMs * 10) / 10,
|
||||
poolHitRate: Math.round(bm.poolHitRate * 1000) / 1000,
|
||||
h2Failures: bm.h2Failures,
|
||||
h2Suppressed: cache.h2Suppressed,
|
||||
h3Suppressed: cache.h3Suppressed,
|
||||
h2CooldownRemainingSecs: cache.h2CooldownRemainingSecs,
|
||||
h3CooldownRemainingSecs: cache.h3CooldownRemainingSecs,
|
||||
h2ConsecutiveFailures: cache.h2ConsecutiveFailures,
|
||||
h3ConsecutiveFailures: cache.h3ConsecutiveFailures,
|
||||
h3Port: cache.h3Port,
|
||||
cacheAgeSecs: cache.ageSecs,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Include protocol cache entries with no matching backend metric
|
||||
for (const entry of protocolCache) {
|
||||
const key = `${entry.host}:${entry.port}`;
|
||||
if (!seen.has(key)) {
|
||||
const compositeKey = `${entry.host}:${entry.port}:${entry.domain ?? ''}`;
|
||||
if (!seenCacheKeys.has(compositeKey)) {
|
||||
backends.push({
|
||||
backend: key,
|
||||
backend: `${entry.host}:${entry.port}`,
|
||||
domain: entry.domain,
|
||||
protocol: entry.protocol,
|
||||
activeConnections: 0,
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@serve.zone/dcrouter',
|
||||
version: '11.10.2',
|
||||
version: '11.10.4',
|
||||
description: 'A multifaceted routing service handling mail and SMS delivery functions.'
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user