@push.rocks/smartproxy 25.9.2 → 25.10.2
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 +25 -0
- package/dist_rust/rustproxy_linux_amd64 +0 -0
- package/dist_rust/rustproxy_linux_arm64 +0 -0
- package/dist_ts/00_commitinfo_data.js +2 -2
- package/dist_ts/proxies/smart-proxy/models/metrics-types.d.ts +22 -0
- package/dist_ts/proxies/smart-proxy/rust-metrics-adapter.d.ts +9 -1
- package/dist_ts/proxies/smart-proxy/rust-metrics-adapter.js +50 -1
- package/package.json +1 -1
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/proxies/smart-proxy/models/metrics-types.ts +22 -0
- package/ts/proxies/smart-proxy/rust-metrics-adapter.ts +50 -1
package/changelog.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2026-03-12 - 25.10.2 - fix(repo)
|
|
4
|
+
no code changes to release
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
## 2026-03-12 - 25.10.1 - fix(repo)
|
|
8
|
+
no changes to commit
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
## 2026-03-12 - 25.10.0 - feat(metrics)
|
|
12
|
+
add per-backend connection, error, protocol, and pool metrics with stale backend pruning
|
|
13
|
+
|
|
14
|
+
- tracks backend connection lifecycle, connect timing, protocol detection, pool hit/miss rates, handshake/request errors, and h2 fallback failures in Rust metrics
|
|
15
|
+
- exposes backend metrics through the TypeScript metrics adapter with backend listings, protocol lookup, and top error summaries
|
|
16
|
+
- prunes backend metrics for backends no longer referenced by active routes, including preserved-port targets expanded across listening ports
|
|
17
|
+
|
|
18
|
+
## 2026-03-11 - 25.9.3 - fix(rustproxy-http)
|
|
19
|
+
Evict stale HTTP/2 pooled senders and retry bodyless requests with fresh backend connections to avoid 502s
|
|
20
|
+
|
|
21
|
+
- Introduce MAX_H2_AGE (120s) and evict HTTP/2 senders older than this or closed
|
|
22
|
+
- Check MAX_H2_AGE on checkout and during background eviction to prevent reuse of stale h2 connections
|
|
23
|
+
- Add connection_pool.remove_h2() to explicitly remove dead H2 senders from the pool
|
|
24
|
+
- When a pooled H2 request returns a 502 and the original request had an empty body, retry using a fresh H2 connection (retry_h2_with_fresh_connection)
|
|
25
|
+
- On H2 auto-detect failures, retry as HTTP/1.1 for bodyless requests via forward_h1_empty_body; return 502 for requests with bodies
|
|
26
|
+
- Evict dead H2 senders on backend request failures in reconnect_backend so subsequent attempts create fresh connections
|
|
27
|
+
|
|
3
28
|
## 2026-03-08 - 25.9.2 - fix(protocol-cache)
|
|
4
29
|
Include requested_host in protocol detection cache key to avoid cache oscillation when multiple frontend domains share the same backend
|
|
5
30
|
|
|
Binary file
|
|
Binary file
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@push.rocks/smartproxy',
|
|
6
|
-
version: '25.
|
|
6
|
+
version: '25.10.2',
|
|
7
7
|
description: 'A powerful proxy package with unified route-based configuration for high traffic management. Features include SSL/TLS support, flexible routing patterns, WebSocket handling, advanced security options, and automatic ACME certificate management.'
|
|
8
8
|
};
|
|
9
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
9
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSx3QkFBd0I7SUFDOUIsT0FBTyxFQUFFLFNBQVM7SUFDbEIsV0FBVyxFQUFFLHFQQUFxUDtDQUNuUSxDQUFBIn0=
|
|
@@ -59,6 +59,14 @@ export interface IMetrics {
|
|
|
59
59
|
bytesOut(): number;
|
|
60
60
|
connections(): number;
|
|
61
61
|
};
|
|
62
|
+
backends: {
|
|
63
|
+
byBackend(): Map<string, IBackendMetrics>;
|
|
64
|
+
protocols(): Map<string, string>;
|
|
65
|
+
topByErrors(limit?: number): Array<{
|
|
66
|
+
backend: string;
|
|
67
|
+
errors: number;
|
|
68
|
+
}>;
|
|
69
|
+
};
|
|
62
70
|
percentiles: {
|
|
63
71
|
connectionDuration(): {
|
|
64
72
|
p50: number;
|
|
@@ -93,6 +101,20 @@ export interface IMetricsConfig {
|
|
|
93
101
|
prometheusPath: string;
|
|
94
102
|
prometheusPrefix: string;
|
|
95
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* Per-backend metrics
|
|
106
|
+
*/
|
|
107
|
+
export interface IBackendMetrics {
|
|
108
|
+
protocol: string;
|
|
109
|
+
activeConnections: number;
|
|
110
|
+
totalConnections: number;
|
|
111
|
+
connectErrors: number;
|
|
112
|
+
handshakeErrors: number;
|
|
113
|
+
requestErrors: number;
|
|
114
|
+
avgConnectTimeMs: number;
|
|
115
|
+
poolHitRate: number;
|
|
116
|
+
h2Failures: number;
|
|
117
|
+
}
|
|
96
118
|
/**
|
|
97
119
|
* Internal interface for connection byte tracking
|
|
98
120
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IMetrics, IThroughputData, IThroughputHistoryPoint } from './models/metrics-types.js';
|
|
1
|
+
import type { IMetrics, IBackendMetrics, IThroughputData, IThroughputHistoryPoint } from './models/metrics-types.js';
|
|
2
2
|
import type { RustProxyBridge } from './rust-proxy-bridge.js';
|
|
3
3
|
/**
|
|
4
4
|
* Adapts Rust JSON metrics to the IMetrics interface.
|
|
@@ -52,6 +52,14 @@ export declare class RustMetricsAdapter implements IMetrics {
|
|
|
52
52
|
bytesOut: () => number;
|
|
53
53
|
connections: () => number;
|
|
54
54
|
};
|
|
55
|
+
backends: {
|
|
56
|
+
byBackend: () => Map<string, IBackendMetrics>;
|
|
57
|
+
protocols: () => Map<string, string>;
|
|
58
|
+
topByErrors: (limit?: number) => Array<{
|
|
59
|
+
backend: string;
|
|
60
|
+
errors: number;
|
|
61
|
+
}>;
|
|
62
|
+
};
|
|
55
63
|
percentiles: {
|
|
56
64
|
connectionDuration: () => {
|
|
57
65
|
p50: number;
|
|
@@ -125,6 +125,55 @@ export class RustMetricsAdapter {
|
|
|
125
125
|
return this.cache?.totalConnections ?? 0;
|
|
126
126
|
},
|
|
127
127
|
};
|
|
128
|
+
this.backends = {
|
|
129
|
+
byBackend: () => {
|
|
130
|
+
const result = new Map();
|
|
131
|
+
if (this.cache?.backends) {
|
|
132
|
+
for (const [key, bm] of Object.entries(this.cache.backends)) {
|
|
133
|
+
const m = bm;
|
|
134
|
+
const totalTimeUs = m.totalConnectTimeUs ?? 0;
|
|
135
|
+
const count = m.connectCount ?? 0;
|
|
136
|
+
const poolHits = m.poolHits ?? 0;
|
|
137
|
+
const poolMisses = m.poolMisses ?? 0;
|
|
138
|
+
const poolTotal = poolHits + poolMisses;
|
|
139
|
+
result.set(key, {
|
|
140
|
+
protocol: m.protocol ?? 'unknown',
|
|
141
|
+
activeConnections: m.activeConnections ?? 0,
|
|
142
|
+
totalConnections: m.totalConnections ?? 0,
|
|
143
|
+
connectErrors: m.connectErrors ?? 0,
|
|
144
|
+
handshakeErrors: m.handshakeErrors ?? 0,
|
|
145
|
+
requestErrors: m.requestErrors ?? 0,
|
|
146
|
+
avgConnectTimeMs: count > 0 ? (totalTimeUs / count) / 1000 : 0,
|
|
147
|
+
poolHitRate: poolTotal > 0 ? poolHits / poolTotal : 0,
|
|
148
|
+
h2Failures: m.h2Failures ?? 0,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return result;
|
|
153
|
+
},
|
|
154
|
+
protocols: () => {
|
|
155
|
+
const result = new Map();
|
|
156
|
+
if (this.cache?.backends) {
|
|
157
|
+
for (const [key, bm] of Object.entries(this.cache.backends)) {
|
|
158
|
+
result.set(key, bm.protocol ?? 'unknown');
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return result;
|
|
162
|
+
},
|
|
163
|
+
topByErrors: (limit = 10) => {
|
|
164
|
+
const result = [];
|
|
165
|
+
if (this.cache?.backends) {
|
|
166
|
+
for (const [key, bm] of Object.entries(this.cache.backends)) {
|
|
167
|
+
const m = bm;
|
|
168
|
+
const errors = (m.connectErrors ?? 0) + (m.handshakeErrors ?? 0) + (m.requestErrors ?? 0);
|
|
169
|
+
if (errors > 0)
|
|
170
|
+
result.push({ backend: key, errors });
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
result.sort((a, b) => b.errors - a.errors);
|
|
174
|
+
return result.slice(0, limit);
|
|
175
|
+
},
|
|
176
|
+
};
|
|
128
177
|
this.percentiles = {
|
|
129
178
|
connectionDuration: () => {
|
|
130
179
|
return { p50: 0, p95: 0, p99: 0 };
|
|
@@ -169,4 +218,4 @@ export class RustMetricsAdapter {
|
|
|
169
218
|
}
|
|
170
219
|
}
|
|
171
220
|
}
|
|
172
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
221
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVzdC1tZXRyaWNzLWFkYXB0ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9wcm94aWVzL3NtYXJ0LXByb3h5L3J1c3QtbWV0cmljcy1hZGFwdGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUdBOzs7Ozs7Ozs7O0dBVUc7QUFDSCxNQUFNLE9BQU8sa0JBQWtCO0lBTTdCLFlBQVksTUFBdUIsRUFBRSxjQUFjLEdBQUcsSUFBSTtRQUpsRCxVQUFLLEdBQVEsSUFBSSxDQUFDO1FBQ2xCLGNBQVMsR0FBMEMsSUFBSSxDQUFDO1FBc0NoRSxrQ0FBa0M7UUFFM0IsZ0JBQVcsR0FBRztZQUNuQixNQUFNLEVBQUUsR0FBVyxFQUFFO2dCQUNuQixPQUFPLElBQUksQ0FBQyxLQUFLLEVBQUUsaUJBQWlCLElBQUksQ0FBQyxDQUFDO1lBQzVDLENBQUM7WUFDRCxLQUFLLEVBQUUsR0FBVyxFQUFFO2dCQUNsQixPQUFPLElBQUksQ0FBQyxLQUFLLEVBQUUsZ0JBQWdCLElBQUksQ0FBQyxDQUFDO1lBQzNDLENBQUM7WUFDRCxPQUFPLEVBQUUsR0FBd0IsRUFBRTtnQkFDakMsTUFBTSxNQUFNLEdBQUcsSUFBSSxHQUFHLEVBQWtCLENBQUM7Z0JBQ3pDLElBQUksSUFBSSxDQUFDLEtBQUssRUFBRSxNQUFNLEVBQUUsQ0FBQztvQkFDdkIsS0FBSyxNQUFNLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO3dCQUMzRCxNQUFNLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRyxFQUFVLENBQUMsaUJBQWlCLElBQUksQ0FBQyxDQUFDLENBQUM7b0JBQ3ZELENBQUM7Z0JBQ0gsQ0FBQztnQkFDRCxPQUFPLE1BQU0sQ0FBQztZQUNoQixDQUFDO1lBQ0QsSUFBSSxFQUFFLEdBQXdCLEVBQUU7Z0JBQzlCLE1BQU0sTUFBTSxHQUFHLElB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
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@push.rocks/smartproxy",
|
|
3
|
-
"version": "25.
|
|
3
|
+
"version": "25.10.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A powerful proxy package with unified route-based configuration for high traffic management. Features include SSL/TLS support, flexible routing patterns, WebSocket handling, advanced security options, and automatic ACME certificate management.",
|
|
6
6
|
"main": "dist_ts/index.js",
|
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@push.rocks/smartproxy',
|
|
6
|
-
version: '25.
|
|
6
|
+
version: '25.10.2',
|
|
7
7
|
description: 'A powerful proxy package with unified route-based configuration for high traffic management. Features include SSL/TLS support, flexible routing patterns, WebSocket handling, advanced security options, and automatic ACME certificate management.'
|
|
8
8
|
}
|
|
@@ -67,6 +67,13 @@ export interface IMetrics {
|
|
|
67
67
|
connections(): number;
|
|
68
68
|
};
|
|
69
69
|
|
|
70
|
+
// Backend metrics
|
|
71
|
+
backends: {
|
|
72
|
+
byBackend(): Map<string, IBackendMetrics>;
|
|
73
|
+
protocols(): Map<string, string>;
|
|
74
|
+
topByErrors(limit?: number): Array<{ backend: string; errors: number }>;
|
|
75
|
+
};
|
|
76
|
+
|
|
70
77
|
// Performance metrics
|
|
71
78
|
percentiles: {
|
|
72
79
|
connectionDuration(): { p50: number; p95: number; p99: number };
|
|
@@ -98,6 +105,21 @@ export interface IMetricsConfig {
|
|
|
98
105
|
prometheusPrefix: string; // Default: smartproxy_
|
|
99
106
|
}
|
|
100
107
|
|
|
108
|
+
/**
|
|
109
|
+
* Per-backend metrics
|
|
110
|
+
*/
|
|
111
|
+
export interface IBackendMetrics {
|
|
112
|
+
protocol: string;
|
|
113
|
+
activeConnections: number;
|
|
114
|
+
totalConnections: number;
|
|
115
|
+
connectErrors: number;
|
|
116
|
+
handshakeErrors: number;
|
|
117
|
+
requestErrors: number;
|
|
118
|
+
avgConnectTimeMs: number;
|
|
119
|
+
poolHitRate: number;
|
|
120
|
+
h2Failures: number;
|
|
121
|
+
}
|
|
122
|
+
|
|
101
123
|
/**
|
|
102
124
|
* Internal interface for connection byte tracking
|
|
103
125
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IMetrics, IThroughputData, IThroughputHistoryPoint } from './models/metrics-types.js';
|
|
1
|
+
import type { IMetrics, IBackendMetrics, IThroughputData, IThroughputHistoryPoint } from './models/metrics-types.js';
|
|
2
2
|
import type { RustProxyBridge } from './rust-proxy-bridge.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -169,6 +169,55 @@ export class RustMetricsAdapter implements IMetrics {
|
|
|
169
169
|
},
|
|
170
170
|
};
|
|
171
171
|
|
|
172
|
+
public backends = {
|
|
173
|
+
byBackend: (): Map<string, IBackendMetrics> => {
|
|
174
|
+
const result = new Map<string, IBackendMetrics>();
|
|
175
|
+
if (this.cache?.backends) {
|
|
176
|
+
for (const [key, bm] of Object.entries(this.cache.backends)) {
|
|
177
|
+
const m = bm as any;
|
|
178
|
+
const totalTimeUs = m.totalConnectTimeUs ?? 0;
|
|
179
|
+
const count = m.connectCount ?? 0;
|
|
180
|
+
const poolHits = m.poolHits ?? 0;
|
|
181
|
+
const poolMisses = m.poolMisses ?? 0;
|
|
182
|
+
const poolTotal = poolHits + poolMisses;
|
|
183
|
+
result.set(key, {
|
|
184
|
+
protocol: m.protocol ?? 'unknown',
|
|
185
|
+
activeConnections: m.activeConnections ?? 0,
|
|
186
|
+
totalConnections: m.totalConnections ?? 0,
|
|
187
|
+
connectErrors: m.connectErrors ?? 0,
|
|
188
|
+
handshakeErrors: m.handshakeErrors ?? 0,
|
|
189
|
+
requestErrors: m.requestErrors ?? 0,
|
|
190
|
+
avgConnectTimeMs: count > 0 ? (totalTimeUs / count) / 1000 : 0,
|
|
191
|
+
poolHitRate: poolTotal > 0 ? poolHits / poolTotal : 0,
|
|
192
|
+
h2Failures: m.h2Failures ?? 0,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return result;
|
|
197
|
+
},
|
|
198
|
+
protocols: (): Map<string, string> => {
|
|
199
|
+
const result = new Map<string, string>();
|
|
200
|
+
if (this.cache?.backends) {
|
|
201
|
+
for (const [key, bm] of Object.entries(this.cache.backends)) {
|
|
202
|
+
result.set(key, (bm as any).protocol ?? 'unknown');
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return result;
|
|
206
|
+
},
|
|
207
|
+
topByErrors: (limit: number = 10): Array<{ backend: string; errors: number }> => {
|
|
208
|
+
const result: Array<{ backend: string; errors: number }> = [];
|
|
209
|
+
if (this.cache?.backends) {
|
|
210
|
+
for (const [key, bm] of Object.entries(this.cache.backends)) {
|
|
211
|
+
const m = bm as any;
|
|
212
|
+
const errors = (m.connectErrors ?? 0) + (m.handshakeErrors ?? 0) + (m.requestErrors ?? 0);
|
|
213
|
+
if (errors > 0) result.push({ backend: key, errors });
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
result.sort((a, b) => b.errors - a.errors);
|
|
217
|
+
return result.slice(0, limit);
|
|
218
|
+
},
|
|
219
|
+
};
|
|
220
|
+
|
|
172
221
|
public percentiles = {
|
|
173
222
|
connectionDuration: (): { p50: number; p95: number; p99: number } => {
|
|
174
223
|
return { p50: 0, p95: 0, p99: 0 };
|