Skip to content

Commit 12cd930

Browse files
committed
Set up an auto-shutdown timer to clean up dangling server instances
1 parent 321f516 commit 12cd930

File tree

1 file changed

+30
-2
lines changed

1 file changed

+30
-2
lines changed

src/index.ts

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ import updateCommand from '@oclif/plugin-update/lib/commands/update';
1919
import { HttpToolkitServerApi } from './api/api-server';
2020
import { checkBrowserConfig } from './browsers';
2121
import { logError } from './error-tracking';
22-
import { MOCKTTP_ALLOWED_ORIGINS } from './constants';
22+
import { IS_PROD_BUILD, MOCKTTP_ALLOWED_ORIGINS } from './constants';
2323

2424
import { delay } from './util/promise';
2525
import { isErrorLike } from './util/error';
2626
import { readFile, checkAccess, writeFile, ensureDirectoryExists } from './util/fs';
2727

28-
import { registerShutdownHandler } from './shutdown';
28+
import { registerShutdownHandler, shutdown } from './shutdown';
2929
import { getTimeToCertExpiry, parseCert } from './certificates';
3030

3131
import {
@@ -77,14 +77,24 @@ function checkCertExpiry(certContents: string): void {
7777
}
7878
}
7979

80+
let shutdownTimer: NodeJS.Timeout | undefined;
81+
8082
function manageBackgroundServices(
8183
standalone: PluggableAdmin.AdminServer<{
8284
http: MockttpAdminPlugin,
8385
webrtc: MockRTCAdminPlugin
8486
}>,
8587
httpsConfig: { certPath: string, certContent: string }
8688
) {
89+
let activeSessions = 0;
90+
8791
standalone.on('mock-session-started', async ({ http, webrtc }, sessionId) => {
92+
activeSessions += 1;
93+
if (shutdownTimer) {
94+
clearTimeout(shutdownTimer);
95+
shutdownTimer = undefined;
96+
}
97+
8898
const httpProxyPort = http.getMockServer().port;
8999

90100
console.log(`Mock session started, http on port ${
@@ -105,6 +115,7 @@ function manageBackgroundServices(
105115
});
106116

107117
standalone.on('mock-session-stopping', ({ http }) => {
118+
activeSessions -= 1;
108119
const httpProxyPort = http.getMockServer().port;
109120

110121
stopDockerInterceptionServices(httpProxyPort, ruleParameters)
@@ -113,6 +124,23 @@ function manageBackgroundServices(
113124
});
114125

115126
clearWebExtensionConfig(httpProxyPort);
127+
128+
// In some odd cases, the server can end up running even though all UIs & desktop have exited
129+
// completely. This can be problematic, as it leaves the server holding ports that HTTP Toolkit
130+
// needs, and blocks future startups. To avoid this, if no Mock sessions are running at all
131+
// for 10 minutes, the server shuts down automatically. Skipped for dev, where that might be OK.
132+
// This should catch even hard desktop shell crashes, as sessions shut down automatically if the
133+
// client websocket becomes non-responsive.
134+
if (activeSessions <= 0 && IS_PROD_BUILD) {
135+
if (shutdownTimer) {
136+
clearTimeout(shutdownTimer);
137+
shutdownTimer = undefined;
138+
}
139+
140+
shutdownTimer = setTimeout(() => {
141+
if (activeSessions === 0) shutdown('10 minutes inactive');
142+
}, 1000 * 60 * 10).unref();
143+
}
116144
});
117145
}
118146

0 commit comments

Comments
 (0)