Skip to content

Commit 692c574

Browse files
committed
Make Docker tunnel port refresh more reliable & performant
1 parent 6ecdcb6 commit 692c574

File tree

1 file changed

+19
-7
lines changed

1 file changed

+19
-7
lines changed

src/interceptors/docker/docker-tunnel-proxy.ts

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import * as Docker from 'dockerode';
33
import * as semver from 'semver';
44
import { Mutex } from 'async-mutex';
55

6+
import { delay } from '../../util/promise';
7+
68
import { DOCKER_HOST_HOSTNAME, isImageAvailable } from './docker-commands';
79
import { isDockerAvailable } from './docker-interception-services';
810

@@ -106,8 +108,18 @@ export function ensureDockerTunnelRunning(proxyPort: number) {
106108
await docker.getContainer(container.Id).start();
107109
}
108110

109-
// Asynchronously, update the Docker port that's in use for this container.
110-
portCache[proxyPort] = refreshDockerTunnelPortCache(proxyPort);
111+
const containerPortMappings = container.NetworkSettings.Ports['1080/tcp'];
112+
const localTunnelPort = _.find(containerPortMappings, ({ HostIp }) => HostIp === '127.0.0.1');
113+
if (!_.isObject(portCache[proxyPort]) && localTunnelPort?.HostPort !== String(portCache[proxyPort])) {
114+
// If the tunnel port may be outdated (port changed, or missing, or container just started so
115+
// port here is undefined) then schedule an async tunnel port refresh:
116+
portCache[proxyPort] = delay(10).then(() => // Leave time for the port to bind
117+
refreshDockerTunnelPortCache(proxyPort, {
118+
// Force, because otherwise we get into a loop here due to the delay().
119+
force: true
120+
})
121+
);
122+
}
111123
}).finally(() => {
112124
// Clean up the promise, so that future calls to ensureRunning re-run this check.
113125
ongoingEnsureTunnelRunningChecks[proxyPort] = undefined;
@@ -191,9 +203,9 @@ export async function getDockerTunnelPort(proxyPort: number): Promise<number> {
191203
return portCache[proxyPort]!;
192204
}
193205

194-
export async function refreshDockerTunnelPortCache(proxyPort: number): Promise<number> {
206+
export async function refreshDockerTunnelPortCache(proxyPort: number, { force } = { force: false }): Promise<number> {
195207
try {
196-
if (_.isObject(portCache[proxyPort])) {
208+
if (!force && _.isObject(portCache[proxyPort])) {
197209
// If there's an existing promise refreshing this data, then don't duplicate:
198210
return portCache[proxyPort]!
199211
}
@@ -205,8 +217,8 @@ export async function refreshDockerTunnelPortCache(proxyPort: number): Promise<n
205217
.inspect().catch(() => undefined);
206218
if (!container) {
207219
// Can't get the container - recreate it (refreshing the port automatically)
208-
await ensureDockerTunnelRunning(proxyPort)
209-
return getDockerTunnelPort(proxyPort);
220+
await ensureDockerTunnelRunning(proxyPort);
221+
return refreshDockerTunnelPortCache(proxyPort, { force: true });
210222
}
211223

212224
const portMappings = container.NetworkSettings.Ports['1080/tcp'];
@@ -217,7 +229,7 @@ export async function refreshDockerTunnelPortCache(proxyPort: number): Promise<n
217229
// this can result in the mapping being lots. Kill & restart the container.
218230
await docker.getContainer(containerName).kill();
219231
await ensureDockerTunnelRunning(proxyPort);
220-
return getDockerTunnelPort(proxyPort);
232+
return refreshDockerTunnelPortCache(proxyPort, { force: true });
221233
}
222234

223235
const port = parseInt(localPort.HostPort, 10);

0 commit comments

Comments
 (0)