@push.rocks/smartproxy 19.5.25 → 19.6.0
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_ts/plugins.d.ts +2 -1
- package/dist_ts/plugins.js +3 -2
- package/dist_ts/proxies/smart-proxy/connection-manager.js +71 -4
- package/dist_ts/proxies/smart-proxy/metrics-collector.d.ts +79 -0
- package/dist_ts/proxies/smart-proxy/metrics-collector.js +235 -0
- package/dist_ts/proxies/smart-proxy/models/index.d.ts +1 -0
- package/dist_ts/proxies/smart-proxy/models/index.js +2 -1
- package/dist_ts/proxies/smart-proxy/models/metrics-types.d.ts +55 -0
- package/dist_ts/proxies/smart-proxy/models/metrics-types.js +2 -0
- package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +2 -1
- package/dist_ts/proxies/smart-proxy/route-connection-handler.js +9 -1
- package/dist_ts/proxies/smart-proxy/smart-proxy.d.ts +12 -2
- package/dist_ts/proxies/smart-proxy/smart-proxy.js +17 -1
- package/package.json +18 -8
- package/readme.connections.md +49 -1
- package/readme.md +118 -0
- package/readme.metrics.md +591 -0
- package/ts/plugins.ts +2 -0
- package/ts/proxies/smart-proxy/connection-manager.ts +11 -3
- package/ts/proxies/smart-proxy/metrics-collector.ts +285 -0
- package/ts/proxies/smart-proxy/models/index.ts +1 -0
- package/ts/proxies/smart-proxy/models/metrics-types.ts +54 -0
- package/ts/proxies/smart-proxy/route-connection-handler.ts +13 -0
- package/ts/proxies/smart-proxy/smart-proxy.ts +27 -2
package/readme.connections.md
CHANGED
|
@@ -673,4 +673,52 @@ if (!record.connectionClosed && record.outgoing && record.bytesReceived > 0 && r
|
|
|
673
673
|
- Connection is older than 60 seconds
|
|
674
674
|
- Both sockets are still alive (not destroyed)
|
|
675
675
|
|
|
676
|
-
This complements the zombie detection by handling cases where sockets remain technically alive but the connection is effectively dead.
|
|
676
|
+
This complements the zombie detection by handling cases where sockets remain technically alive but the connection is effectively dead.
|
|
677
|
+
|
|
678
|
+
## 🚨 CRITICAL FIX: Cleanup Queue Bug (January 2025)
|
|
679
|
+
|
|
680
|
+
### Critical Bug Found
|
|
681
|
+
The cleanup queue had a severe bug that caused connection accumulation when more than 100 connections needed cleanup:
|
|
682
|
+
|
|
683
|
+
```typescript
|
|
684
|
+
// BUG: This cleared the ENTIRE queue after processing only the first batch!
|
|
685
|
+
const toCleanup = Array.from(this.cleanupQueue).slice(0, this.cleanupBatchSize);
|
|
686
|
+
this.cleanupQueue.clear(); // ❌ This discarded all connections beyond the first 100!
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
### Fix Implemented
|
|
690
|
+
```typescript
|
|
691
|
+
// Now only removes the connections being processed
|
|
692
|
+
const toCleanup = Array.from(this.cleanupQueue).slice(0, this.cleanupBatchSize);
|
|
693
|
+
for (const connectionId of toCleanup) {
|
|
694
|
+
this.cleanupQueue.delete(connectionId); // ✅ Only remove what we process
|
|
695
|
+
const record = this.connectionRecords.get(connectionId);
|
|
696
|
+
if (record) {
|
|
697
|
+
this.cleanupConnection(record, record.incomingTerminationReason || 'normal');
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
```
|
|
701
|
+
|
|
702
|
+
### Impact
|
|
703
|
+
- **Before**: If 150 connections needed cleanup, only the first 100 would be processed and the remaining 50 would accumulate forever
|
|
704
|
+
- **After**: All connections are properly cleaned up in batches
|
|
705
|
+
|
|
706
|
+
### Additional Improvements
|
|
707
|
+
|
|
708
|
+
1. **Faster Inactivity Checks**: Reduced from 30s to 10s intervals
|
|
709
|
+
- Zombies and stuck connections are detected 3x faster
|
|
710
|
+
- Reduces the window for accumulation
|
|
711
|
+
|
|
712
|
+
2. **Duplicate Prevention**: Added check in queueCleanup to prevent processing already-closed connections
|
|
713
|
+
- Prevents unnecessary work
|
|
714
|
+
- Ensures connections are only cleaned up once
|
|
715
|
+
|
|
716
|
+
### Summary of All Fixes
|
|
717
|
+
|
|
718
|
+
1. **Connection Timeout** (already documented) - Prevents accumulation when backends are unreachable
|
|
719
|
+
2. **Zombie Detection** - Cleans up connections with destroyed sockets
|
|
720
|
+
3. **Stuck Connection Detection** - Cleans up connections to hanging backends
|
|
721
|
+
4. **Cleanup Queue Bug** - Ensures ALL connections get cleaned up, not just the first 100
|
|
722
|
+
5. **Faster Detection** - Reduced check interval from 30s to 10s
|
|
723
|
+
|
|
724
|
+
These fixes combined should prevent connection accumulation in all known scenarios.
|
package/readme.md
CHANGED
|
@@ -919,6 +919,124 @@ Available helper functions:
|
|
|
919
919
|
})
|
|
920
920
|
```
|
|
921
921
|
|
|
922
|
+
## Metrics and Monitoring
|
|
923
|
+
|
|
924
|
+
SmartProxy includes a comprehensive metrics collection system that provides real-time insights into proxy performance, connection statistics, and throughput data.
|
|
925
|
+
|
|
926
|
+
### Getting Metrics
|
|
927
|
+
|
|
928
|
+
```typescript
|
|
929
|
+
const proxy = new SmartProxy({ /* config */ });
|
|
930
|
+
await proxy.start();
|
|
931
|
+
|
|
932
|
+
// Access metrics through the getStats() method
|
|
933
|
+
const stats = proxy.getStats();
|
|
934
|
+
|
|
935
|
+
// Get current active connections
|
|
936
|
+
console.log(`Active connections: ${stats.getActiveConnections()}`);
|
|
937
|
+
|
|
938
|
+
// Get total connections since start
|
|
939
|
+
console.log(`Total connections: ${stats.getTotalConnections()}`);
|
|
940
|
+
|
|
941
|
+
// Get requests per second (RPS)
|
|
942
|
+
console.log(`Current RPS: ${stats.getRequestsPerSecond()}`);
|
|
943
|
+
|
|
944
|
+
// Get throughput data
|
|
945
|
+
const throughput = stats.getThroughput();
|
|
946
|
+
console.log(`Bytes received: ${throughput.bytesIn}`);
|
|
947
|
+
console.log(`Bytes sent: ${throughput.bytesOut}`);
|
|
948
|
+
|
|
949
|
+
// Get connections by route
|
|
950
|
+
const routeConnections = stats.getConnectionsByRoute();
|
|
951
|
+
for (const [route, count] of routeConnections) {
|
|
952
|
+
console.log(`Route ${route}: ${count} connections`);
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
// Get connections by IP address
|
|
956
|
+
const ipConnections = stats.getConnectionsByIP();
|
|
957
|
+
for (const [ip, count] of ipConnections) {
|
|
958
|
+
console.log(`IP ${ip}: ${count} connections`);
|
|
959
|
+
}
|
|
960
|
+
```
|
|
961
|
+
|
|
962
|
+
### Available Metrics
|
|
963
|
+
|
|
964
|
+
The `IProxyStats` interface provides the following methods:
|
|
965
|
+
|
|
966
|
+
- `getActiveConnections()`: Current number of active connections
|
|
967
|
+
- `getTotalConnections()`: Total connections handled since proxy start
|
|
968
|
+
- `getRequestsPerSecond()`: Current requests per second (1-minute average)
|
|
969
|
+
- `getThroughput()`: Total bytes transferred (in/out)
|
|
970
|
+
- `getConnectionsByRoute()`: Connection count per route
|
|
971
|
+
- `getConnectionsByIP()`: Connection count per client IP
|
|
972
|
+
|
|
973
|
+
### Monitoring Example
|
|
974
|
+
|
|
975
|
+
```typescript
|
|
976
|
+
// Create a monitoring loop
|
|
977
|
+
setInterval(() => {
|
|
978
|
+
const stats = proxy.getStats();
|
|
979
|
+
|
|
980
|
+
// Log key metrics
|
|
981
|
+
console.log({
|
|
982
|
+
timestamp: new Date().toISOString(),
|
|
983
|
+
activeConnections: stats.getActiveConnections(),
|
|
984
|
+
rps: stats.getRequestsPerSecond(),
|
|
985
|
+
throughput: stats.getThroughput()
|
|
986
|
+
});
|
|
987
|
+
|
|
988
|
+
// Check for high connection counts from specific IPs
|
|
989
|
+
const ipConnections = stats.getConnectionsByIP();
|
|
990
|
+
for (const [ip, count] of ipConnections) {
|
|
991
|
+
if (count > 100) {
|
|
992
|
+
console.warn(`High connection count from ${ip}: ${count}`);
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
}, 10000); // Every 10 seconds
|
|
996
|
+
```
|
|
997
|
+
|
|
998
|
+
### Exporting Metrics
|
|
999
|
+
|
|
1000
|
+
You can export metrics in various formats for external monitoring systems:
|
|
1001
|
+
|
|
1002
|
+
```typescript
|
|
1003
|
+
// Export as JSON
|
|
1004
|
+
app.get('/metrics.json', (req, res) => {
|
|
1005
|
+
const stats = proxy.getStats();
|
|
1006
|
+
res.json({
|
|
1007
|
+
activeConnections: stats.getActiveConnections(),
|
|
1008
|
+
totalConnections: stats.getTotalConnections(),
|
|
1009
|
+
requestsPerSecond: stats.getRequestsPerSecond(),
|
|
1010
|
+
throughput: stats.getThroughput(),
|
|
1011
|
+
connectionsByRoute: Object.fromEntries(stats.getConnectionsByRoute()),
|
|
1012
|
+
connectionsByIP: Object.fromEntries(stats.getConnectionsByIP())
|
|
1013
|
+
});
|
|
1014
|
+
});
|
|
1015
|
+
|
|
1016
|
+
// Export as Prometheus format
|
|
1017
|
+
app.get('/metrics', (req, res) => {
|
|
1018
|
+
const stats = proxy.getStats();
|
|
1019
|
+
res.set('Content-Type', 'text/plain');
|
|
1020
|
+
res.send(`
|
|
1021
|
+
# HELP smartproxy_active_connections Current active connections
|
|
1022
|
+
# TYPE smartproxy_active_connections gauge
|
|
1023
|
+
smartproxy_active_connections ${stats.getActiveConnections()}
|
|
1024
|
+
|
|
1025
|
+
# HELP smartproxy_requests_per_second Current requests per second
|
|
1026
|
+
# TYPE smartproxy_requests_per_second gauge
|
|
1027
|
+
smartproxy_requests_per_second ${stats.getRequestsPerSecond()}
|
|
1028
|
+
|
|
1029
|
+
# HELP smartproxy_bytes_in Total bytes received
|
|
1030
|
+
# TYPE smartproxy_bytes_in counter
|
|
1031
|
+
smartproxy_bytes_in ${stats.getThroughput().bytesIn}
|
|
1032
|
+
|
|
1033
|
+
# HELP smartproxy_bytes_out Total bytes sent
|
|
1034
|
+
# TYPE smartproxy_bytes_out counter
|
|
1035
|
+
smartproxy_bytes_out ${stats.getThroughput().bytesOut}
|
|
1036
|
+
`);
|
|
1037
|
+
});
|
|
1038
|
+
```
|
|
1039
|
+
|
|
922
1040
|
## Other Components
|
|
923
1041
|
|
|
924
1042
|
While SmartProxy provides a unified API for most needs, you can also use individual components:
|