Skip to content

Commit 0992b24

Browse files
committed
fix tracking server leak
1 parent 2d94bb5 commit 0992b24

File tree

3 files changed

+31
-25
lines changed

3 files changed

+31
-25
lines changed

src/main/script.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,9 @@ export const runScript = async ({
100100
K6_BROWSER_ARGS: proxyArgs.join(','),
101101
K6_TESTING_COLORIZE: 'false',
102102
},
103+
disposables: [trackingServer],
103104
})
104105

105-
testRun.addDisposable(trackingServer)
106-
107106
testRun.on('log', ({ entry }) => {
108107
browserWindow.webContents.send(ScriptHandler.Log, entry)
109108
})

src/utils/k6/client.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ interface RunArgs {
4949
insecureSkipTLSVerify?: boolean
5050
noUsageReport?: boolean
5151
env?: Record<string, string>
52+
disposables?: Array<AsyncDisposable | Disposable>
5253
}
5354

5455
export class ArchiveError extends Error {
@@ -119,6 +120,7 @@ export class K6Client {
119120
insecureSkipTLSVerify,
120121
noUsageReport,
121122
env = {},
123+
disposables = [],
122124
}: RunArgs): TestRun {
123125
const args = [
124126
['--log-format', 'json'],
@@ -133,7 +135,7 @@ export class K6Client {
133135
env,
134136
})
135137

136-
return new TestRun(process)
138+
return new TestRun(process, disposables)
137139
}
138140

139141
#wait(k6: ChildProcessWithoutNullStreams): Promise<SpawnResult> {

src/utils/k6/testRun.ts

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ interface TestRunEventMap {
115115
* Called when the test run has stopped, i.e. after the
116116
* done, abort or error events have been emitted.
117117
*/
118-
stop: void
118+
stop: EmptyObject
119119

120120
/**
121121
* Fired when a log entry is emitted by the test run.
@@ -125,13 +125,20 @@ interface TestRunEventMap {
125125

126126
export class TestRun extends EventEmitter<TestRunEventMap> {
127127
#process: ChildProcessWithoutNullStreams
128+
#disposer = new AsyncDisposableStack()
128129

129130
#checks: Check[] = []
130-
#disposables: Array<AsyncDisposable | Disposable> = []
131131

132-
constructor(process: ChildProcessWithoutNullStreams) {
132+
constructor(
133+
process: ChildProcessWithoutNullStreams,
134+
disposables: Array<AsyncDisposable | Disposable> = []
135+
) {
133136
super()
134137

138+
for (const disposable of disposables) {
139+
this.#disposer.use(disposable)
140+
}
141+
135142
process.on('spawn', this.#handleStart)
136143

137144
process.on('error', this.#handleError)
@@ -168,26 +175,22 @@ export class TestRun extends EventEmitter<TestRunEventMap> {
168175

169176
this.#process = process
170177

171-
this.on('done', this.#emitStop)
172-
this.on('abort', this.#emitStop)
173-
this.on('error', this.#emitStop)
178+
this.on('done', this.#handleStop)
179+
this.on('abort', this.#handleStop)
180+
this.on('error', this.#handleStop)
174181
}
175182

176183
isRunning(): boolean {
177184
return this.#process.pid != undefined && this.#process.exitCode === null
178185
}
179186

180187
async stop(): Promise<void> {
181-
await Promise.all([
182-
this.#kill(),
183-
...this.#disposables.map((disposable) => {
184-
if (Symbol.asyncDispose in disposable) {
185-
return disposable[Symbol.asyncDispose]()
186-
}
187-
188-
return disposable[Symbol.dispose]()
189-
}),
190-
])
188+
// If we encounter an error while disposing we assume the resources have already
189+
// been disposed and ignore the error. `disposeAsync` is idempotent so calling it
190+
// multiple times is safe.
191+
await Promise.allSettled([this.#kill(), this.#disposer.disposeAsync()])
192+
193+
this.emit('stop', {})
191194
}
192195

193196
#kill() {
@@ -252,11 +255,13 @@ export class TestRun extends EventEmitter<TestRunEventMap> {
252255
}
253256
}
254257

255-
#emitStop = () => {
256-
this.emit('stop', undefined)
257-
}
258-
259-
addDisposable(disposable: AsyncDisposable | Disposable) {
260-
this.#disposables.push(disposable)
258+
#handleStop = async () => {
259+
try {
260+
await this.#disposer.disposeAsync()
261+
} catch (error) {
262+
console.error('Error disposing children of test run', error)
263+
} finally {
264+
this.emit('stop', {})
265+
}
261266
}
262267
}

0 commit comments

Comments
 (0)