Bound public API connection lifetimes

This commit is contained in:
Ben
2026-08-04 19:20:48 -04:00
parent 7d96c06bbf
commit d1ebc55871
5 changed files with 47 additions and 8 deletions
+7
View File
@@ -32,6 +32,13 @@ API_PORT=3334
API_BIND_HOST=127.0.0.1 API_BIND_HOST=127.0.0.1
API_PUBLIC_PORT=3334 API_PUBLIC_PORT=3334
API_WORKERS=4 API_WORKERS=4
# Bound abandoned or slow API sockets. These settings apply only to the
# HTTP(S) listener and do not affect Stratum connections.
API_CONNECTION_TIMEOUT_MS=15000
API_KEEP_ALIVE_TIMEOUT_MS=5000
API_REQUEST_TIMEOUT_MS=15000
API_HEADERS_TIMEOUT_MS=10000
API_MAX_REQUESTS_PER_SOCKET=100
# Docker json-file log rotation. Applies when using the compose files. # Docker json-file log rotation. Applies when using the compose files.
DOCKER_LOG_MAX_SIZE=100m DOCKER_LOG_MAX_SIZE=100m
+5
View File
@@ -74,6 +74,11 @@ services:
API_PORT: ${API_PORT:-3334} API_PORT: ${API_PORT:-3334}
API_SECURE: ${API_SECURE:-false} API_SECURE: ${API_SECURE:-false}
API_WORKERS: ${API_WORKERS:-4} API_WORKERS: ${API_WORKERS:-4}
API_CONNECTION_TIMEOUT_MS: ${API_CONNECTION_TIMEOUT_MS:-15000}
API_KEEP_ALIVE_TIMEOUT_MS: ${API_KEEP_ALIVE_TIMEOUT_MS:-5000}
API_REQUEST_TIMEOUT_MS: ${API_REQUEST_TIMEOUT_MS:-15000}
API_HEADERS_TIMEOUT_MS: ${API_HEADERS_TIMEOUT_MS:-10000}
API_MAX_REQUESTS_PER_SOCKET: ${API_MAX_REQUESTS_PER_SOCKET:-100}
PM2_ENABLED: ${PM2_ENABLED:-true} PM2_ENABLED: ${PM2_ENABLED:-true}
STRATUM_WORKERS: ${STRATUM_WORKERS:-auto} STRATUM_WORKERS: ${STRATUM_WORKERS:-auto}
STRATUM_PORTS: ${STRATUM_PORTS:-3333,3332,3331,3330} STRATUM_PORTS: ${STRATUM_PORTS:-3333,3332,3331,3330}
+5
View File
@@ -104,6 +104,11 @@ services:
API_PORT: ${API_PORT:-3334} API_PORT: ${API_PORT:-3334}
API_SECURE: ${API_SECURE:-false} API_SECURE: ${API_SECURE:-false}
API_WORKERS: ${API_WORKERS:-4} API_WORKERS: ${API_WORKERS:-4}
API_CONNECTION_TIMEOUT_MS: ${API_CONNECTION_TIMEOUT_MS:-15000}
API_KEEP_ALIVE_TIMEOUT_MS: ${API_KEEP_ALIVE_TIMEOUT_MS:-5000}
API_REQUEST_TIMEOUT_MS: ${API_REQUEST_TIMEOUT_MS:-15000}
API_HEADERS_TIMEOUT_MS: ${API_HEADERS_TIMEOUT_MS:-10000}
API_MAX_REQUESTS_PER_SOCKET: ${API_MAX_REQUESTS_PER_SOCKET:-100}
PM2_ENABLED: ${PM2_ENABLED:-true} PM2_ENABLED: ${PM2_ENABLED:-true}
STRATUM_WORKERS: ${STRATUM_WORKERS:-auto} STRATUM_WORKERS: ${STRATUM_WORKERS:-auto}
STRATUM_PORTS: ${STRATUM_PORTS:-3333,3332,3331,3330} STRATUM_PORTS: ${STRATUM_PORTS:-3333,3332,3331,3330}
+5
View File
@@ -108,6 +108,11 @@ services:
DB_DATABASE: public_pool_mainnet DB_DATABASE: public_pool_mainnet
REDIS_URL: redis://redis:6379 REDIS_URL: redis://redis:6379
API_WORKERS: ${API_WORKERS:-4} API_WORKERS: ${API_WORKERS:-4}
API_CONNECTION_TIMEOUT_MS: ${API_CONNECTION_TIMEOUT_MS:-15000}
API_KEEP_ALIVE_TIMEOUT_MS: ${API_KEEP_ALIVE_TIMEOUT_MS:-5000}
API_REQUEST_TIMEOUT_MS: ${API_REQUEST_TIMEOUT_MS:-15000}
API_HEADERS_TIMEOUT_MS: ${API_HEADERS_TIMEOUT_MS:-10000}
API_MAX_REQUESTS_PER_SOCKET: ${API_MAX_REQUESTS_PER_SOCKET:-100}
PM2_ENABLED: "true" PM2_ENABLED: "true"
STRATUM_WORKERS: ${STRATUM_WORKERS:-2} STRATUM_WORKERS: ${STRATUM_WORKERS:-2}
STRATUM_MIN_DIFFICULTY: ${STRATUM_MIN_DIFFICULTY:-1} STRATUM_MIN_DIFFICULTY: ${STRATUM_MIN_DIFFICULTY:-1}
+25 -8
View File
@@ -10,6 +10,17 @@ import * as ecc from 'tiny-secp256k1';
import { ApiModule } from './api.module'; import { ApiModule } from './api.module';
import { AppModule } from './app.module'; import { AppModule } from './app.module';
const DEFAULT_API_CONNECTION_TIMEOUT_MS = 15_000;
const DEFAULT_API_KEEP_ALIVE_TIMEOUT_MS = 5_000;
const DEFAULT_API_REQUEST_TIMEOUT_MS = 15_000;
const DEFAULT_API_HEADERS_TIMEOUT_MS = 10_000;
const DEFAULT_API_MAX_REQUESTS_PER_SOCKET = 100;
function readPositiveInt(name: string, fallback: number): number {
const value = Number(process.env[name]);
return Number.isInteger(value) && value > 0 ? value : fallback;
}
async function bootstrap() { async function bootstrap() {
if (process.env.API_PORT == null) { if (process.env.API_PORT == null) {
console.error('It appears your environment is not configured, create and populate an .env file.'); console.error('It appears your environment is not configured, create and populate an .env file.');
@@ -23,13 +34,18 @@ async function bootstrap() {
const keyPath = path.join(currentDirectory, 'secrets', 'key.pem'); const keyPath = path.join(currentDirectory, 'secrets', 'key.pem');
const certPath = path.join(currentDirectory, 'secrets', 'cert.pem'); const certPath = path.join(currentDirectory, 'secrets', 'cert.pem');
let options: any = {}; let options: any = serveApi
? {
connectionTimeout: readPositiveInt('API_CONNECTION_TIMEOUT_MS', DEFAULT_API_CONNECTION_TIMEOUT_MS),
keepAliveTimeout: readPositiveInt('API_KEEP_ALIVE_TIMEOUT_MS', DEFAULT_API_KEEP_ALIVE_TIMEOUT_MS),
requestTimeout: readPositiveInt('API_REQUEST_TIMEOUT_MS', DEFAULT_API_REQUEST_TIMEOUT_MS),
maxRequestsPerSocket: readPositiveInt('API_MAX_REQUESTS_PER_SOCKET', DEFAULT_API_MAX_REQUESTS_PER_SOCKET),
}
: {};
if (secure) { if (secure) {
options = { options.https = {
https: { key: readFileSync(keyPath),
key: readFileSync(keyPath), cert: readFileSync(certPath),
cert: readFileSync(certPath),
}
}; };
} }
@@ -75,11 +91,12 @@ async function bootstrap() {
console.log(`API listening on ${address}`); console.log(`API listening on ${address}`);
}); });
const server: any = app.getHttpServer();
server.headersTimeout = readPositiveInt('API_HEADERS_TIMEOUT_MS', DEFAULT_API_HEADERS_TIMEOUT_MS);
// --- Live-reload TLS certs/keys when they change on disk --- // --- Live-reload TLS certs/keys when they change on disk ---
if (secure) { if (secure) {
// Fastify's underlying Node https server // Fastify's underlying Node https server
const server: any = app.getHttpServer();
// Guard: only HTTPS servers expose setSecureContext // Guard: only HTTPS servers expose setSecureContext
if (typeof server?.setSecureContext === 'function') { if (typeof server?.setSecureContext === 'function') {
let reloadTimer: NodeJS.Timeout | null = null; let reloadTimer: NodeJS.Timeout | null = null;