@@ -3,6 +3,8 @@ import * as Docker from 'dockerode';
3
3
import * as semver from 'semver' ;
4
4
import { Mutex } from 'async-mutex' ;
5
5
6
+ import { delay } from '../../util/promise' ;
7
+
6
8
import { DOCKER_HOST_HOSTNAME , isImageAvailable } from './docker-commands' ;
7
9
import { isDockerAvailable } from './docker-interception-services' ;
8
10
@@ -106,8 +108,18 @@ export function ensureDockerTunnelRunning(proxyPort: number) {
106
108
await docker . getContainer ( container . Id ) . start ( ) ;
107
109
}
108
110
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
+ }
111
123
} ) . finally ( ( ) => {
112
124
// Clean up the promise, so that future calls to ensureRunning re-run this check.
113
125
ongoingEnsureTunnelRunningChecks [ proxyPort ] = undefined ;
@@ -191,9 +203,9 @@ export async function getDockerTunnelPort(proxyPort: number): Promise<number> {
191
203
return portCache [ proxyPort ] ! ;
192
204
}
193
205
194
- export async function refreshDockerTunnelPortCache ( proxyPort : number ) : Promise < number > {
206
+ export async function refreshDockerTunnelPortCache ( proxyPort : number , { force } = { force : false } ) : Promise < number > {
195
207
try {
196
- if ( _ . isObject ( portCache [ proxyPort ] ) ) {
208
+ if ( ! force && _ . isObject ( portCache [ proxyPort ] ) ) {
197
209
// If there's an existing promise refreshing this data, then don't duplicate:
198
210
return portCache [ proxyPort ] !
199
211
}
@@ -205,8 +217,8 @@ export async function refreshDockerTunnelPortCache(proxyPort: number): Promise<n
205
217
. inspect ( ) . catch ( ( ) => undefined ) ;
206
218
if ( ! container ) {
207
219
// 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 } ) ;
210
222
}
211
223
212
224
const portMappings = container . NetworkSettings . Ports [ '1080/tcp' ] ;
@@ -217,7 +229,7 @@ export async function refreshDockerTunnelPortCache(proxyPort: number): Promise<n
217
229
// this can result in the mapping being lots. Kill & restart the container.
218
230
await docker . getContainer ( containerName ) . kill ( ) ;
219
231
await ensureDockerTunnelRunning ( proxyPort ) ;
220
- return getDockerTunnelPort ( proxyPort ) ;
232
+ return refreshDockerTunnelPortCache ( proxyPort , { force : true } ) ;
221
233
}
222
234
223
235
const port = parseInt ( localPort . HostPort , 10 ) ;
0 commit comments