Compare commits
3 Commits
Author | SHA1 | Date | |
---|---|---|---|
22418cd65e | |||
86b016cac3 | |||
e81d0386d6 |
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@push.rocks/smartproxy",
|
||||
"version": "19.6.8",
|
||||
"version": "19.6.9",
|
||||
"private": false,
|
||||
"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.",
|
||||
"main": "dist_ts/index.js",
|
||||
|
@ -0,0 +1,57 @@
|
||||
# SmartProxy Development Hints
|
||||
|
||||
## Byte Tracking and Metrics
|
||||
|
||||
### Double Counting Issue (Fixed)
|
||||
|
||||
**Problem**: Initial data chunks were being counted twice in the byte tracking:
|
||||
1. Once when stored in `pendingData` in `setupDirectConnection()`
|
||||
2. Again when the data flowed through bidirectional forwarding
|
||||
|
||||
**Solution**: Removed the byte counting when storing initial chunks. Bytes are now only counted when they actually flow through the `setupBidirectionalForwarding()` callbacks.
|
||||
|
||||
### HttpProxy Metrics (Fixed)
|
||||
|
||||
**Problem**: HttpProxy forwarding was updating connection record byte counts but not calling `metricsCollector.recordBytes()`, resulting in missing throughput data.
|
||||
|
||||
**Solution**: Added `metricsCollector.recordBytes()` calls to the HttpProxy bidirectional forwarding callbacks.
|
||||
|
||||
### Metrics Architecture
|
||||
|
||||
The metrics system has three layers:
|
||||
1. **Connection Records** (`record.bytesReceived/bytesSent`): Track total bytes per connection
|
||||
2. **ThroughputTracker**: Accumulates bytes between samples for rate calculations (bytes/second)
|
||||
3. **connectionByteTrackers**: Track bytes per connection with timestamps for per-route/IP metrics
|
||||
|
||||
Total byte counts come from connection records only, preventing double counting.
|
||||
|
||||
## Connection Cleanup
|
||||
|
||||
### Zombie Connection Detection
|
||||
|
||||
The connection manager performs comprehensive zombie detection every 10 seconds:
|
||||
- **Full zombies**: Both incoming and outgoing sockets destroyed but connection not cleaned up
|
||||
- **Half zombies**: One socket destroyed, grace period expired (5 minutes for TLS, 30 seconds for non-TLS)
|
||||
- **Stuck connections**: Data received but none sent back after threshold (5 minutes for TLS, 60 seconds for non-TLS)
|
||||
|
||||
### Cleanup Queue
|
||||
|
||||
Connections are cleaned up through a batched queue system:
|
||||
- Batch size: 100 connections
|
||||
- Processing triggered immediately when batch size reached
|
||||
- Otherwise processed after 100ms delay
|
||||
- Prevents overwhelming the system during mass disconnections
|
||||
|
||||
## Keep-Alive Handling
|
||||
|
||||
Keep-alive connections receive special treatment based on `keepAliveTreatment` setting:
|
||||
- **standard**: Normal timeout applies
|
||||
- **extended**: Timeout multiplied by `keepAliveInactivityMultiplier` (default 6x)
|
||||
- **immortal**: No timeout, connections persist indefinitely
|
||||
|
||||
## PROXY Protocol
|
||||
|
||||
The system supports both receiving and sending PROXY protocol:
|
||||
- **Receiving**: Automatically detected from trusted proxy IPs (configured in `proxyIPs`)
|
||||
- **Sending**: Enabled per-route or globally via `sendProxyProtocol` setting
|
||||
- Real client IP is preserved and used for all connection tracking and security checks
|
@ -135,12 +135,20 @@ export class HttpProxyBridge {
|
||||
// Update stats if needed
|
||||
if (record) {
|
||||
record.bytesReceived += chunk.length;
|
||||
// Also record in metrics collector for throughput tracking
|
||||
if (this.smartProxy.metricsCollector) {
|
||||
this.smartProxy.metricsCollector.recordBytes(record.id, chunk.length, 0);
|
||||
}
|
||||
}
|
||||
},
|
||||
onServerData: (chunk) => {
|
||||
// Update stats if needed
|
||||
if (record) {
|
||||
record.bytesSent += chunk.length;
|
||||
// Also record in metrics collector for throughput tracking
|
||||
if (this.smartProxy.metricsCollector) {
|
||||
this.smartProxy.metricsCollector.recordBytes(record.id, 0, chunk.length);
|
||||
}
|
||||
}
|
||||
},
|
||||
onCleanup: (reason) => {
|
||||
|
@ -1114,14 +1114,9 @@ export class RouteConnectionHandler {
|
||||
|
||||
// Store initial data if provided
|
||||
if (initialChunk) {
|
||||
record.bytesReceived += initialChunk.length;
|
||||
// Don't count bytes here - they will be counted when actually forwarded through bidirectional forwarding
|
||||
record.pendingData.push(Buffer.from(initialChunk));
|
||||
record.pendingDataSize = initialChunk.length;
|
||||
|
||||
// Record bytes for metrics
|
||||
if (this.smartProxy.metricsCollector) {
|
||||
this.smartProxy.metricsCollector.recordBytes(record.id, initialChunk.length, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Create the target socket with immediate error handling
|
||||
|
Reference in New Issue
Block a user