prevent half connections staying open

This commit is contained in:
Ben
2026-05-30 19:24:34 -04:00
parent c5169e105e
commit 4cab56a1a0
7 changed files with 68 additions and 2 deletions
+26
View File
@@ -6,6 +6,8 @@ describe('StratumV1Service', () => {
const originalStratumSecure = process.env.STRATUM_SECURE;
const originalSecureStratumPorts = process.env.SECURE_STRATUM_PORTS;
const originalBackpressureEnabled = process.env.STRATUM_BACKPRESSURE_ENABLED;
const originalMaxConnectionsPerListener = process.env.STRATUM_MAX_CONNECTIONS_PER_LISTENER;
const originalTlsHandshakeTimeoutMs = process.env.STRATUM_TLS_HANDSHAKE_TIMEOUT_MS;
let service: StratumV1Service;
let clientService;
@@ -37,6 +39,8 @@ describe('StratumV1Service', () => {
restoreEnv('STRATUM_SECURE', originalStratumSecure);
restoreEnv('SECURE_STRATUM_PORTS', originalSecureStratumPorts);
restoreEnv('STRATUM_BACKPRESSURE_ENABLED', originalBackpressureEnabled);
restoreEnv('STRATUM_MAX_CONNECTIONS_PER_LISTENER', originalMaxConnectionsPerListener);
restoreEnv('STRATUM_TLS_HANDSHAKE_TIMEOUT_MS', originalTlsHandshakeTimeoutMs);
consoleLogSpy.mockRestore();
consoleWarnSpy.mockRestore();
jest.useRealTimers();
@@ -119,6 +123,28 @@ describe('StratumV1Service', () => {
expect(consoleWarnSpy).toHaveBeenCalledWith(expect.stringContaining('Resuming Stratum accepts'));
});
it('should cap listener connections and drop excess cluster connections', () => {
process.env.STRATUM_MAX_CONNECTIONS_PER_LISTENER = '250';
const server = {} as any;
(service as any).configureConnectionLimit(server);
expect(server.maxConnections).toBe(250);
expect(server.dropMaxConnection).toBe(true);
});
it('should allow high-volume pools by default', () => {
delete process.env.STRATUM_MAX_CONNECTIONS_PER_LISTENER;
expect((service as any).getMaxConnectionsPerListener()).toBe(10000);
});
it('should use an explicit TLS handshake timeout', () => {
process.env.STRATUM_TLS_HANDSHAKE_TIMEOUT_MS = '5000';
expect((service as any).getTlsHandshakeTimeoutMs()).toBe(5000);
});
function restoreEnv(key: string, value: string | undefined) {
if (value == null) {
delete process.env[key];
+18
View File
@@ -29,6 +29,8 @@ const DEFAULT_BACKPRESSURE_EVENT_LOOP_RESUME_P95_MS = 250;
const DEFAULT_BACKPRESSURE_RSS_MB = 2500;
const DEFAULT_BACKPRESSURE_RESUME_RSS_MB = 2000;
const DEFAULT_BACKPRESSURE_HEALTHY_CHECKS = 3;
const DEFAULT_MAX_CONNECTIONS_PER_LISTENER = 10000;
const DEFAULT_TLS_HANDSHAKE_TIMEOUT_MS = 10000;
@@ -162,6 +164,7 @@ export class StratumV1Service implements OnModuleInit {
server.on('error', (err) => {
console.error(`Server error: ${err.message}`);
});
this.configureConnectionLimit(server);
return server;
}
@@ -186,6 +189,7 @@ export class StratumV1Service implements OnModuleInit {
const tlsOptions: TlsOptions = {
key: readFileSync(keyPath),
cert: readFileSync(certPath),
handshakeTimeout: this.getTlsHandshakeTimeoutMs()
};
const server = createServer(tlsOptions, async (socket: TLSSocket) => {
@@ -242,6 +246,7 @@ export class StratumV1Service implements OnModuleInit {
server.on('error', (err) => {
console.error(`Server error: ${err.message}`);
});
this.configureConnectionLimit(server);
return server;
@@ -371,6 +376,19 @@ export class StratumV1Service implements OnModuleInit {
return this.getPositiveIntegerEnv('STRATUM_BACKPRESSURE_HEALTHY_CHECKS', DEFAULT_BACKPRESSURE_HEALTHY_CHECKS);
}
private configureConnectionLimit(server: Server) {
server.maxConnections = this.getMaxConnectionsPerListener();
(server as Server & { dropMaxConnection: boolean }).dropMaxConnection = true;
}
private getMaxConnectionsPerListener() {
return this.getPositiveIntegerEnv('STRATUM_MAX_CONNECTIONS_PER_LISTENER', DEFAULT_MAX_CONNECTIONS_PER_LISTENER);
}
private getTlsHandshakeTimeoutMs() {
return this.getPositiveIntegerEnv('STRATUM_TLS_HANDSHAKE_TIMEOUT_MS', DEFAULT_TLS_HANDSHAKE_TIMEOUT_MS);
}
private getPositiveIntegerEnv(key: string, fallback: number) {
const configured = parseInt(process.env[key], 10);
if (Number.isFinite(configured) && configured > 0) {