Skip to content

Commit cebd1a9

Browse files
committed
feat: Provide "ready helpers" as ReadyContext methods
1 parent e1ddd9b commit cebd1a9

File tree

12 files changed

+67
-159
lines changed

12 files changed

+67
-159
lines changed

src/Service.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ import { PassThrough } from 'stream'
33
import cloneable from 'cloneable-readable'
44
import { ServiceProcess } from './ServiceProcess'
55
import { NormalizedServiceConfig } from './validateAndNormalizeConfig'
6-
import { ReadyContext } from './interfaces/ReadyContext'
76
import { OnCrashContext } from './interfaces/OnCrashContext'
87
import { ServiceCrash } from './interfaces/ServiceCrash'
98
import { InternalError } from './InternalError'
109
import { Logger } from './Logger'
10+
import { createReadyContext } from './createReadyContext'
1111

1212
const delay = promisify(setTimeout)
1313

@@ -57,9 +57,7 @@ export class Service {
5757
}
5858

5959
private defineReady() {
60-
const ctx: ReadyContext = {
61-
output: this.outputClone,
62-
}
60+
const ctx = createReadyContext(this.outputClone)
6361
this.ready = promiseTry(() => this.config.ready(ctx))
6462
.finally(() => this.outputClone.destroy())
6563
.catch(error => {

src/createReadyContext.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { promisify } from 'util'
2+
import stream from 'stream'
3+
import { ReadyContext } from './interfaces/ReadyContext'
4+
import { onceTcpPortUsed } from './util/onceTcpPortUsed'
5+
6+
const delay = promisify(setTimeout)
7+
8+
export function createReadyContext(output: stream.Readable): ReadyContext {
9+
return {
10+
onceTcpPortUsed,
11+
onceOutputLineIs: line => onceOutputLine(output, l => l === line),
12+
onceOutputLineIncludes: text =>
13+
onceOutputLine(output, l => l.includes(text)),
14+
onceOutputLine: test => onceOutputLine(output, test),
15+
onceDelay: milliseconds => delay(milliseconds),
16+
}
17+
}
18+
19+
function onceOutputLine(
20+
output: stream.Readable,
21+
test: (line: string) => boolean,
22+
): Promise<void> {
23+
return new Promise<void>(resolve => {
24+
const handler = (line: string) => {
25+
if (test(line)) {
26+
output.off('data', handler)
27+
resolve()
28+
}
29+
}
30+
output.on('data', handler)
31+
})
32+
}

src/index.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
export * from './ready-helpers'
2-
31
export { startCompositeService } from './startCompositeService'
42

53
export { CompositeServiceConfig } from './interfaces/CompositeServiceConfig'

src/interfaces/ReadyContext.ts

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,33 @@
1-
import stream from 'stream'
2-
31
/**
42
* Context object given as argument to each {@link ServiceConfig.ready} function
53
*/
64
export interface ReadyContext {
75
/**
8-
* Interleaved lines from stdout & stderr of the service.
9-
*
10-
* Each chunk is a utf8 string ending in '\n'.
6+
* Wait until the given TCP `port` (on the given `host`) is accepting connections.
7+
* The `port` is required.
8+
* The `host` defaults to "localhost".
119
*
12-
* Can be used `as AsyncIterable<string>`.
10+
* Works by trying establish a TCP connection to the given port every 250 milliseconds.
11+
*/
12+
onceTcpPortUsed: (port: number | string, host?: string) => Promise<void>
13+
14+
/**
15+
* Wait until a line in the console output passes custom `test`
16+
*/
17+
onceOutputLine: (test: (line: string) => boolean) => Promise<void>
18+
19+
/**
20+
* Wait until a certain exact `line` appears in the console output
21+
*/
22+
onceOutputLineIs: (line: string) => Promise<void>
23+
24+
/**
25+
* Wait until a line including `text` appears in the console output
26+
*/
27+
onceOutputLineIncludes: (text: string) => Promise<void>
28+
29+
/**
30+
* Wait a predetermined length of time
1331
*/
14-
output: stream.Readable
32+
onceDelay: (milliseconds: number) => Promise<void>
1533
}

src/interfaces/ServiceConfig.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,6 @@ export interface ServiceConfig {
5858
*
5959
* If any error is encountered in its execution,
6060
* the composite service will shut down any running services and exit.
61-
*
62-
* This library includes a collection of [Ready Helpers](./composite-service.oncetcpportused.md)
63-
* to help you define this property.
6461
*/
6562
ready?: (ctx: ReadyContext) => Promise<any>
6663

src/ready-helpers/index.ts

Lines changed: 0 additions & 3 deletions
This file was deleted.

src/ready-helpers/output-line.ts

Lines changed: 0 additions & 81 deletions
This file was deleted.

src/ready-helpers/timeout.ts

Lines changed: 0 additions & 25 deletions
This file was deleted.
Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,32 +3,6 @@ import { Socket } from 'net'
33

44
const delay = promisify(setTimeout)
55

6-
/**
7-
* Waits until the given `port` (on the given `host`) is accepting connections
8-
*
9-
* @remarks
10-
*
11-
* Works by trying to connect to the given port
12-
* (as opposed to trying to listen on the given port)
13-
* every 250 milliseconds.
14-
*
15-
* @param port -
16-
* @param host - Defaults to `'localhost'`
17-
*
18-
* @example
19-
*
20-
* ```js
21-
* const { onceTcpPortUsed } = require('composite-service')
22-
*
23-
* const myServiceConfig = {
24-
* command: 'node server.js',
25-
* env: { PORT: 3000 },
26-
* ready: () => onceTcpPortUsed(3000),
27-
* }
28-
* ```
29-
*
30-
* @public
31-
*/
326
export async function onceTcpPortUsed(
337
port: number | string,
348
host = 'localhost',

test/integration/crashing.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ const delay = (time: number) =>
88

99
function getScript(customCode = '') {
1010
return `
11-
const { startCompositeService, onceOutputLineIs } = require('.');
11+
const { startCompositeService } = require('.');
1212
const config = {
1313
logLevel: 'debug',
1414
gracefulShutdown: true,
1515
serviceDefaults: {
1616
command: 'node test/integration/fixtures/http-service.js',
17-
ready: ctx => onceOutputLineIs(ctx.output, 'Started 🚀\\n'),
17+
ready: ctx => ctx.onceOutputLineIs('Started 🚀\\n'),
1818
},
1919
services: {
2020
first: {

0 commit comments

Comments
 (0)