1
+ import { setTimeout } from 'timers/promises' ;
1
2
import { WebSocket } from 'ws' ;
2
3
import * as dockerApi from './dockerApi.js' ;
3
4
5
+ async function connectWebSocket ( address : string , deadline : number ) : Promise < WebSocket | undefined > {
6
+ while ( Date . now ( ) < deadline ) {
7
+ const socket = new WebSocket ( address ) ;
8
+ const result = await new Promise < boolean > ( ( resolve , reject ) => {
9
+ socket . on ( 'open' , ( ) => resolve ( true ) ) ;
10
+ socket . on ( 'error' , ( ) => reject ( false ) ) ;
11
+ } ) ;
12
+ if ( result )
13
+ return socket ;
14
+ await setTimeout ( 100 , undefined ) ;
15
+ }
16
+ return undefined ;
17
+ }
18
+
4
19
export class GenericService {
5
20
static async launch ( options : {
6
21
imageName : string ,
@@ -17,7 +32,7 @@ export class GenericService {
17
32
} ) {
18
33
const images = await dockerApi . listImages ( ) ;
19
34
const imageName = options . imageName + '-deadmanswitch' ;
20
- const image = images . find ( image => image . names . includes ( options . imageName ) ) ;
35
+ const image = images . find ( image => image . names . includes ( imageName ) ) ;
21
36
if ( ! image )
22
37
throw new Error ( `ERROR: no image named "${ imageName } " - run 'npx deadmanswitch-pull ${ options . imageName } '` ) ;
23
38
@@ -32,6 +47,7 @@ export class GenericService {
32
47
command : options . command ,
33
48
env : options . env ,
34
49
} ) ;
50
+ const deadline = Date . now ( ) + 10000 ; // 10s is default timeout before deadmanswitch will kill container.
35
51
const container = ( await dockerApi . listContainers ( ) ) . find ( container => container . containerId === containerId ) ;
36
52
if ( ! container )
37
53
throw new Error ( 'ERROR: failed to launch container!' ) ;
@@ -41,17 +57,14 @@ export class GenericService {
41
57
await dockerApi . stopContainer ( { containerId : container . containerId } ) ;
42
58
throw new Error ( 'Failed to expose service to host' ) ;
43
59
}
44
- const ws = new WebSocket ( `ws://localhost:${ switchBinding . hostPort } ` ) ;
45
- const wsConnectionPromise = new Promise < void > ( ( resolve , reject ) => {
46
- ws . on ( 'open' , ( ) => resolve ( ) ) ;
47
- ws . on ( 'error' , reject ) ;
48
- } ) ;
49
- await wsConnectionPromise ;
50
- const service = new GenericService ( containerId , serviceBinding . hostPort , ws ) ;
51
60
52
61
while ( ! ( await dockerApi . isContainerHealthy ( container . containerId ) ) )
53
- await new Promise ( x => setTimeout ( x , 100 ) ) ;
62
+ await setTimeout ( 100 , undefined ) ;
54
63
64
+ const ws = await connectWebSocket ( `ws://localhost:${ switchBinding . hostPort } ` , deadline ) ;
65
+ if ( ! ws )
66
+ throw new Error ( 'Failed to connect to launched container' ) ;
67
+ const service = new GenericService ( containerId , serviceBinding . hostPort , ws ) ;
55
68
return service ;
56
69
}
57
70
0 commit comments