From 9ffe1a872bd5f4af5d9b46cfdc22045c69efb436 Mon Sep 17 00:00:00 2001 From: rafapaezbas Date: Thu, 21 Nov 2024 18:37:52 +0100 Subject: [PATCH 01/38] close worker pipe on renderer pipe.end() --- gui/preload.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gui/preload.js b/gui/preload.js index c234602f8..07d5e30f1 100644 --- a/gui/preload.js +++ b/gui/preload.js @@ -313,6 +313,11 @@ class IPC { }) electron.ipcRenderer.on('workerPipeData', (e, data) => { stream.push(data) }) + + stream.on('finish', () => { + electron.ipcRenderer.send('workerPipeClose', id) + }) + return stream } From b6641b4da7516a2bb0481d11962f077224e56e60 Mon Sep 17 00:00:00 2001 From: rafapaezbas Date: Thu, 21 Nov 2024 23:41:11 +0100 Subject: [PATCH 02/38] final null push to receive end event in renderer worker pipe --- gui/preload.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/gui/preload.js b/gui/preload.js index 07d5e30f1..6cd660566 100644 --- a/gui/preload.js +++ b/gui/preload.js @@ -302,6 +302,10 @@ class IPC { write (data, cb) { electron.ipcRenderer.send('workerPipeWrite', id, data) cb() + }, + final (cb) { + stream.push(null) + cb() } }) electron.ipcRenderer.on('workerPipeError', (e, stack) => { @@ -314,7 +318,7 @@ class IPC { electron.ipcRenderer.on('workerPipeData', (e, data) => { stream.push(data) }) - stream.on('finish', () => { + stream.on('end', () => { electron.ipcRenderer.send('workerPipeClose', id) }) From fb25f3e37d6a837d7cbc0f0e20f2140df59f9948 Mon Sep 17 00:00:00 2001 From: Marco Date: Fri, 22 Nov 2024 21:18:53 +1100 Subject: [PATCH 03/38] improve-worker-close --- gui/gui.js | 27 +++++++++++++-------------- gui/preload.js | 15 ++++++++------- lib/worker.js | 9 ++++++--- 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/gui/gui.js b/gui/gui.js index 22b448b9d..1c3b5bfa2 100644 --- a/gui/gui.js +++ b/gui/gui.js @@ -1490,27 +1490,21 @@ class PearGUI extends ReadyResource { electron.ipcMain.handle('restart', (evt, ...args) => this.restart(...args)) electron.ipcMain.handle('badge', (evt, ...args) => this.badge(...args)) + electron.ipcMain.on('workerPipeId', (evt) => { + evt.returnValue = this.pipes.nextId() + return evt.returnValue + }) + electron.ipcMain.on('workerRun', (evt, link, args) => { const pipe = this.worker.run(link, args) const id = this.pipes.alloc(pipe) + pipe.on('data', (data) => { evt.reply('workerPipeData', data) }) + pipe.on('error', (err) => { evt.reply('workerPipeError', err.stack) }) + pipe.on('end', () => { evt.reply('workerPipeClose') }) pipe.on('close', () => { this.pipes.free(id) evt.reply('workerPipeClose') }) - pipe.on('data', (data) => { evt.reply('workerPipeData', data) }) - pipe.on('end', () => { evt.reply('workerPipeData', null) }) - pipe.on('error', (err) => { evt.reply('pipeError', err.stack) }) - }) - - electron.ipcMain.on('workerPipeId', (evt) => { - evt.returnValue = this.pipes.nextId() - return evt.returnValue - }) - - electron.ipcMain.on('workerPipeClose', (evt, id) => { - const pipe = this.pipes.from(id) - if (!pipe) return - pipe.destroy() }) electron.ipcMain.on('workerPipeWrite', (evt, id, data) => { @@ -1521,6 +1515,11 @@ class PearGUI extends ReadyResource { } pipe.write(data) }) + electron.ipcMain.on('workerPipeClose', (evt, id) => { + const pipe = this.pipes.from(id) + if (!pipe) return + pipe.destroy() + }) } async app () { diff --git a/gui/preload.js b/gui/preload.js index 6cd660566..cfc8e7e1f 100644 --- a/gui/preload.js +++ b/gui/preload.js @@ -297,7 +297,9 @@ class IPC { workerRun (link) { const id = electron.ipcRenderer.sendSync('workerPipeId') + electron.ipcRenderer.send('workerRun', link) + const stream = new streamx.Duplex({ write (data, cb) { electron.ipcRenderer.send('workerPipeWrite', id, data) @@ -308,20 +310,19 @@ class IPC { cb() } }) - electron.ipcRenderer.on('workerPipeError', (e, stack) => { - stream.emit('error', new Error('Worker PipeError (from electron-main): ' + stack)) + stream.on('end', () => { + electron.ipcRenderer.send('workerPipeClose', id) }) - electron.ipcRenderer.on('workerClose', () => { stream.destroy() }) stream.once('close', () => { electron.ipcRenderer.send('workerPipeClose', id) }) electron.ipcRenderer.on('workerPipeData', (e, data) => { stream.push(data) }) - - stream.on('end', () => { - electron.ipcRenderer.send('workerPipeClose', id) + electron.ipcRenderer.on('workerPipeError', (e, stack) => { + stream.emit('error', new Error('Worker PipeError (from electron-main): ' + stack)) }) - + electron.ipcRenderer.on('workerPipeClose', () => { stream.destroy() }) + return stream } diff --git a/lib/worker.js b/lib/worker.js index c146a298f..9ff0e9232 100644 --- a/lib/worker.js +++ b/lib/worker.js @@ -54,7 +54,10 @@ class Worker { }) const pipe = sp.stdio[3] pipe.on('end', () => { - if (pipe.ended === false) pipe.end() + pipe.destroy() + }) + pipe.on('close', () => { + pipe.destroy() }) return pipe } @@ -69,10 +72,10 @@ class Worker { return null } const pipe = new Pipe(fd) + this.#pipe = pipe pipe.on('end', () => { - teardown(() => pipe.end(), Number.MAX_SAFE_INTEGER) + teardown(() => pipe.destroy(), Number.MAX_SAFE_INTEGER) }) - this.#pipe = pipe pipe.once('close', () => { teardown(() => program.exit(), Number.MAX_SAFE_INTEGER) }) From 71084bc7766c806e1cd016a559ce16cd819aa83d Mon Sep 17 00:00:00 2001 From: Marco Date: Fri, 22 Nov 2024 21:33:35 +1100 Subject: [PATCH 04/38] lint --- gui/preload.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gui/preload.js b/gui/preload.js index cfc8e7e1f..7da961e36 100644 --- a/gui/preload.js +++ b/gui/preload.js @@ -322,7 +322,7 @@ class IPC { stream.emit('error', new Error('Worker PipeError (from electron-main): ' + stack)) }) electron.ipcRenderer.on('workerPipeClose', () => { stream.destroy() }) - + return stream } From 8c44d271ead11431e9710360ccc70fabccd6f672 Mon Sep 17 00:00:00 2001 From: Marco Date: Fri, 22 Nov 2024 21:43:05 +1100 Subject: [PATCH 05/38] close once --- gui/gui.js | 2 +- gui/preload.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gui/gui.js b/gui/gui.js index 1c3b5bfa2..e24a8c1e7 100644 --- a/gui/gui.js +++ b/gui/gui.js @@ -1515,7 +1515,7 @@ class PearGUI extends ReadyResource { } pipe.write(data) }) - electron.ipcMain.on('workerPipeClose', (evt, id) => { + electron.ipcMain.once('workerPipeClose', (evt, id) => { const pipe = this.pipes.from(id) if (!pipe) return pipe.destroy() diff --git a/gui/preload.js b/gui/preload.js index 7da961e36..bb546ebe8 100644 --- a/gui/preload.js +++ b/gui/preload.js @@ -321,7 +321,7 @@ class IPC { electron.ipcRenderer.on('workerPipeError', (e, stack) => { stream.emit('error', new Error('Worker PipeError (from electron-main): ' + stack)) }) - electron.ipcRenderer.on('workerPipeClose', () => { stream.destroy() }) + electron.ipcRenderer.once('workerPipeClose', () => { stream.destroy() }) return stream } From 0c512a6b207185d1a8e85a5320811754d3a4745f Mon Sep 17 00:00:00 2001 From: Marco Date: Fri, 22 Nov 2024 21:58:57 +1100 Subject: [PATCH 06/38] comment --- lib/worker.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/worker.js b/lib/worker.js index 9ff0e9232..d2672d525 100644 --- a/lib/worker.js +++ b/lib/worker.js @@ -54,7 +54,8 @@ class Worker { }) const pipe = sp.stdio[3] pipe.on('end', () => { - pipe.destroy() + // should not call pipe.end() here because stream might be closed already when worker calls pipe.destroy() + pipe.destroy() }) pipe.on('close', () => { pipe.destroy() From 5040e108a4f70513682bb07d9c613b4cb4928329 Mon Sep 17 00:00:00 2001 From: Marco Date: Fri, 22 Nov 2024 22:11:03 +1100 Subject: [PATCH 07/38] remove end --- gui/preload.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/gui/preload.js b/gui/preload.js index bb546ebe8..5cf19980f 100644 --- a/gui/preload.js +++ b/gui/preload.js @@ -310,9 +310,6 @@ class IPC { cb() } }) - stream.on('end', () => { - electron.ipcRenderer.send('workerPipeClose', id) - }) stream.once('close', () => { electron.ipcRenderer.send('workerPipeClose', id) }) From d13822eae96e6466e615ecadbae52c62335e4654 Mon Sep 17 00:00:00 2001 From: Marco Date: Fri, 22 Nov 2024 22:34:02 +1100 Subject: [PATCH 08/38] fix lint --- lib/worker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/worker.js b/lib/worker.js index d2672d525..bc584c166 100644 --- a/lib/worker.js +++ b/lib/worker.js @@ -55,7 +55,7 @@ class Worker { const pipe = sp.stdio[3] pipe.on('end', () => { // should not call pipe.end() here because stream might be closed already when worker calls pipe.destroy() - pipe.destroy() + pipe.destroy() }) pipe.on('close', () => { pipe.destroy() From 4d9d04b488da85fbafbddf07ec60fa4de64ff492 Mon Sep 17 00:00:00 2001 From: Marco Date: Sat, 23 Nov 2024 01:06:28 +1100 Subject: [PATCH 09/38] on('error --- lib/worker.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/worker.js b/lib/worker.js index bc584c166..f30f3045a 100644 --- a/lib/worker.js +++ b/lib/worker.js @@ -53,13 +53,15 @@ class Worker { this.#unref() }) const pipe = sp.stdio[3] - pipe.on('end', () => { - // should not call pipe.end() here because stream might be closed already when worker calls pipe.destroy() - pipe.destroy() - }) - pipe.on('close', () => { - pipe.destroy() + pipe.on('error', (err) => { + if (pipe._readableState.ended && err.code === 'ENOTCONN') { + return + } else { + throw err + } }) + pipe.on('end', () => pipe.end()) + pipe.on('close', () => pipe.destroy()) return pipe } From 6e7bb418ebc47dac743d7e698f9ff84068549542 Mon Sep 17 00:00:00 2001 From: Marco Date: Sat, 23 Nov 2024 01:07:11 +1100 Subject: [PATCH 10/38] revert --- gui/gui.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gui/gui.js b/gui/gui.js index e24a8c1e7..4ebfe95b1 100644 --- a/gui/gui.js +++ b/gui/gui.js @@ -1498,13 +1498,13 @@ class PearGUI extends ReadyResource { electron.ipcMain.on('workerRun', (evt, link, args) => { const pipe = this.worker.run(link, args) const id = this.pipes.alloc(pipe) - pipe.on('data', (data) => { evt.reply('workerPipeData', data) }) - pipe.on('error', (err) => { evt.reply('workerPipeError', err.stack) }) - pipe.on('end', () => { evt.reply('workerPipeClose') }) pipe.on('close', () => { this.pipes.free(id) evt.reply('workerPipeClose') }) + pipe.on('data', (data) => { evt.reply('workerPipeData', data) }) + pipe.on('end', () => { evt.reply('workerPipeClose') }) + pipe.on('error', (err) => { evt.reply('workerPipeError', err.stack) }) }) electron.ipcMain.on('workerPipeWrite', (evt, id, data) => { From 0d5970c984ed695dbfe7a2e0ea763f33cba8acea Mon Sep 17 00:00:00 2001 From: Marco Date: Sat, 23 Nov 2024 01:07:48 +1100 Subject: [PATCH 11/38] revert --- gui/gui.js | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/gui/gui.js b/gui/gui.js index 4ebfe95b1..077405a35 100644 --- a/gui/gui.js +++ b/gui/gui.js @@ -1490,10 +1490,6 @@ class PearGUI extends ReadyResource { electron.ipcMain.handle('restart', (evt, ...args) => this.restart(...args)) electron.ipcMain.handle('badge', (evt, ...args) => this.badge(...args)) - electron.ipcMain.on('workerPipeId', (evt) => { - evt.returnValue = this.pipes.nextId() - return evt.returnValue - }) electron.ipcMain.on('workerRun', (evt, link, args) => { const pipe = this.worker.run(link, args) @@ -1503,10 +1499,21 @@ class PearGUI extends ReadyResource { evt.reply('workerPipeClose') }) pipe.on('data', (data) => { evt.reply('workerPipeData', data) }) - pipe.on('end', () => { evt.reply('workerPipeClose') }) + pipe.on('end', () => { evt.reply('workerPipeEnd') }) pipe.on('error', (err) => { evt.reply('workerPipeError', err.stack) }) }) + electron.ipcMain.on('workerPipeId', (evt) => { + evt.returnValue = this.pipes.nextId() + return evt.returnValue + }) + + electron.ipcMain.once('workerPipeClose', (evt, id) => { + const pipe = this.pipes.from(id) + if (!pipe) return + pipe.destroy() + }) + electron.ipcMain.on('workerPipeWrite', (evt, id, data) => { const pipe = this.pipes.from(id) if (!pipe) { @@ -1515,11 +1522,6 @@ class PearGUI extends ReadyResource { } pipe.write(data) }) - electron.ipcMain.once('workerPipeClose', (evt, id) => { - const pipe = this.pipes.from(id) - if (!pipe) return - pipe.destroy() - }) } async app () { From d73bad2a6e303739398914e0316d7033be30ea83 Mon Sep 17 00:00:00 2001 From: Marco Date: Sat, 23 Nov 2024 01:08:15 +1100 Subject: [PATCH 12/38] gui --- gui/gui.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/gui/gui.js b/gui/gui.js index 077405a35..ce280eaec 100644 --- a/gui/gui.js +++ b/gui/gui.js @@ -1490,7 +1490,6 @@ class PearGUI extends ReadyResource { electron.ipcMain.handle('restart', (evt, ...args) => this.restart(...args)) electron.ipcMain.handle('badge', (evt, ...args) => this.badge(...args)) - electron.ipcMain.on('workerRun', (evt, link, args) => { const pipe = this.worker.run(link, args) const id = this.pipes.alloc(pipe) @@ -1507,13 +1506,13 @@ class PearGUI extends ReadyResource { evt.returnValue = this.pipes.nextId() return evt.returnValue }) - + electron.ipcMain.once('workerPipeClose', (evt, id) => { const pipe = this.pipes.from(id) if (!pipe) return pipe.destroy() }) - + electron.ipcMain.on('workerPipeWrite', (evt, id, data) => { const pipe = this.pipes.from(id) if (!pipe) { From b6e419f924428874541daf2951750564a7a922b7 Mon Sep 17 00:00:00 2001 From: Marco Date: Sat, 23 Nov 2024 01:08:33 +1100 Subject: [PATCH 13/38] on --- lib/worker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/worker.js b/lib/worker.js index f30f3045a..352d16182 100644 --- a/lib/worker.js +++ b/lib/worker.js @@ -55,7 +55,7 @@ class Worker { const pipe = sp.stdio[3] pipe.on('error', (err) => { if (pipe._readableState.ended && err.code === 'ENOTCONN') { - return + } else { throw err } From 75d26962f7221767b6da81e84587c4495b620bd2 Mon Sep 17 00:00:00 2001 From: Marco Date: Sat, 23 Nov 2024 01:08:49 +1100 Subject: [PATCH 14/38] on --- gui/gui.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gui/gui.js b/gui/gui.js index ce280eaec..bdd9e2602 100644 --- a/gui/gui.js +++ b/gui/gui.js @@ -1507,7 +1507,7 @@ class PearGUI extends ReadyResource { return evt.returnValue }) - electron.ipcMain.once('workerPipeClose', (evt, id) => { + electron.ipcMain.on('workerPipeClose', (evt, id) => { const pipe = this.pipes.from(id) if (!pipe) return pipe.destroy() From 5c0a66b7c011211fcced06d8622b2900b5732c05 Mon Sep 17 00:00:00 2001 From: Marco Date: Sat, 23 Nov 2024 01:09:59 +1100 Subject: [PATCH 15/38] up --- gui/preload.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/gui/preload.js b/gui/preload.js index 5cf19980f..390f70b7b 100644 --- a/gui/preload.js +++ b/gui/preload.js @@ -297,9 +297,7 @@ class IPC { workerRun (link) { const id = electron.ipcRenderer.sendSync('workerPipeId') - electron.ipcRenderer.send('workerRun', link) - const stream = new streamx.Duplex({ write (data, cb) { electron.ipcRenderer.send('workerPipeWrite', id, data) @@ -310,16 +308,15 @@ class IPC { cb() } }) - stream.once('close', () => { - electron.ipcRenderer.send('workerPipeClose', id) - }) - - electron.ipcRenderer.on('workerPipeData', (e, data) => { stream.push(data) }) electron.ipcRenderer.on('workerPipeError', (e, stack) => { stream.emit('error', new Error('Worker PipeError (from electron-main): ' + stack)) }) electron.ipcRenderer.once('workerPipeClose', () => { stream.destroy() }) + stream.once('close', () => { + electron.ipcRenderer.send('workerPipeClose', id) + }) + electron.ipcRenderer.on('workerPipeData', (e, data) => { stream.push(data) }) return stream } From d245790e48d4330c08f0ae94b5445b5ab3f0d056 Mon Sep 17 00:00:00 2001 From: Marco Date: Sat, 23 Nov 2024 01:10:50 +1100 Subject: [PATCH 16/38] workerPipeEnd --- gui/preload.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gui/preload.js b/gui/preload.js index 390f70b7b..e20c5017a 100644 --- a/gui/preload.js +++ b/gui/preload.js @@ -311,7 +311,8 @@ class IPC { electron.ipcRenderer.on('workerPipeError', (e, stack) => { stream.emit('error', new Error('Worker PipeError (from electron-main): ' + stack)) }) - electron.ipcRenderer.once('workerPipeClose', () => { stream.destroy() }) + electron.ipcRenderer.on('workerPipeEnd', () => { stream.end() }) + electron.ipcRenderer.on('workerPipeClose', () => { stream.destroy() }) stream.once('close', () => { electron.ipcRenderer.send('workerPipeClose', id) }) From 449d0066ba6923ee5c6eb04a3b4e967e7447c149 Mon Sep 17 00:00:00 2001 From: Marco Date: Sat, 23 Nov 2024 01:11:10 +1100 Subject: [PATCH 17/38] end --- lib/worker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/worker.js b/lib/worker.js index 352d16182..32df7a08c 100644 --- a/lib/worker.js +++ b/lib/worker.js @@ -77,7 +77,7 @@ class Worker { const pipe = new Pipe(fd) this.#pipe = pipe pipe.on('end', () => { - teardown(() => pipe.destroy(), Number.MAX_SAFE_INTEGER) + teardown(() => pipe.end(), Number.MAX_SAFE_INTEGER) }) pipe.once('close', () => { teardown(() => program.exit(), Number.MAX_SAFE_INTEGER) From 3aaa8ee1bf69980043c670b79cb71f1e61076f1b Mon Sep 17 00:00:00 2001 From: Marco Date: Sat, 23 Nov 2024 01:12:26 +1100 Subject: [PATCH 18/38] u --- gui/preload.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gui/preload.js b/gui/preload.js index e20c5017a..8a4434128 100644 --- a/gui/preload.js +++ b/gui/preload.js @@ -311,8 +311,8 @@ class IPC { electron.ipcRenderer.on('workerPipeError', (e, stack) => { stream.emit('error', new Error('Worker PipeError (from electron-main): ' + stack)) }) - electron.ipcRenderer.on('workerPipeEnd', () => { stream.end() }) electron.ipcRenderer.on('workerPipeClose', () => { stream.destroy() }) + electron.ipcRenderer.on('workerPipeEnd', () => { stream.end() }) stream.once('close', () => { electron.ipcRenderer.send('workerPipeClose', id) }) From cf38e7caf6401ca3267df253612105a9ef41576f Mon Sep 17 00:00:00 2001 From: Marco Date: Sat, 23 Nov 2024 01:14:34 +1100 Subject: [PATCH 19/38] Warning --- lib/worker.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/worker.js b/lib/worker.js index 32df7a08c..b55d49261 100644 --- a/lib/worker.js +++ b/lib/worker.js @@ -55,7 +55,8 @@ class Worker { const pipe = sp.stdio[3] pipe.on('error', (err) => { if (pipe._readableState.ended && err.code === 'ENOTCONN') { - + console.warn('Warning: ', err) + return } else { throw err } From 871fa13be3d076f52a432ff1a26a3e06d083a51a Mon Sep 17 00:00:00 2001 From: Marco Date: Sat, 23 Nov 2024 01:15:00 +1100 Subject: [PATCH 20/38] move --- lib/worker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/worker.js b/lib/worker.js index b55d49261..8556f1093 100644 --- a/lib/worker.js +++ b/lib/worker.js @@ -76,10 +76,10 @@ class Worker { return null } const pipe = new Pipe(fd) - this.#pipe = pipe pipe.on('end', () => { teardown(() => pipe.end(), Number.MAX_SAFE_INTEGER) }) + this.#pipe = pipe pipe.once('close', () => { teardown(() => program.exit(), Number.MAX_SAFE_INTEGER) }) From 70e0769ad0a5618d87c7b58450cc2f229f107965 Mon Sep 17 00:00:00 2001 From: Marco Date: Sat, 23 Nov 2024 01:53:34 +1100 Subject: [PATCH 21/38] pipe end --- gui/gui.js | 6 ++++++ gui/preload.js | 2 +- lib/worker.js | 1 - 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/gui/gui.js b/gui/gui.js index bdd9e2602..3c2c00245 100644 --- a/gui/gui.js +++ b/gui/gui.js @@ -1507,6 +1507,12 @@ class PearGUI extends ReadyResource { return evt.returnValue }) + electron.ipcMain.on('workerPipeEnd', (evt, id) => { + const pipe = this.pipes.from(id) + if (!pipe) return + pipe.end() + }) + electron.ipcMain.on('workerPipeClose', (evt, id) => { const pipe = this.pipes.from(id) if (!pipe) return diff --git a/gui/preload.js b/gui/preload.js index 8a4434128..84c677549 100644 --- a/gui/preload.js +++ b/gui/preload.js @@ -304,7 +304,7 @@ class IPC { cb() }, final (cb) { - stream.push(null) + electron.ipcRenderer.send('workerPipeEnd', id) cb() } }) diff --git a/lib/worker.js b/lib/worker.js index 8556f1093..f25a612df 100644 --- a/lib/worker.js +++ b/lib/worker.js @@ -56,7 +56,6 @@ class Worker { pipe.on('error', (err) => { if (pipe._readableState.ended && err.code === 'ENOTCONN') { console.warn('Warning: ', err) - return } else { throw err } From 253ecea6ed38104f3b85c6047d9ba94fe4e11673 Mon Sep 17 00:00:00 2001 From: Marco Date: Sat, 23 Nov 2024 01:58:18 +1100 Subject: [PATCH 22/38] add cmt --- lib/worker.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/worker.js b/lib/worker.js index f25a612df..0e60a260c 100644 --- a/lib/worker.js +++ b/lib/worker.js @@ -55,7 +55,8 @@ class Worker { const pipe = sp.stdio[3] pipe.on('error', (err) => { if (pipe._readableState.ended && err.code === 'ENOTCONN') { - console.warn('Warning: ', err) + // this might happen during pipe destruction, ignore it since the pipe is closing soon, + // otherwise the main process will crash } else { throw err } From 00a0ec62e11454e137c160b631dc9c8ed2edb800 Mon Sep 17 00:00:00 2001 From: Marco Date: Sat, 23 Nov 2024 08:12:30 +1100 Subject: [PATCH 23/38] remove close destroy --- lib/worker.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/worker.js b/lib/worker.js index 0e60a260c..20fda2bbb 100644 --- a/lib/worker.js +++ b/lib/worker.js @@ -62,7 +62,6 @@ class Worker { } }) pipe.on('end', () => pipe.end()) - pipe.on('close', () => pipe.destroy()) return pipe } From 5247da586466e3c1bede6beb6ba8f121f18f87be Mon Sep 17 00:00:00 2001 From: Marco Date: Sat, 23 Nov 2024 08:14:44 +1100 Subject: [PATCH 24/38] fx ENOTCONN --- lib/worker.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/lib/worker.js b/lib/worker.js index 20fda2bbb..d1edac412 100644 --- a/lib/worker.js +++ b/lib/worker.js @@ -54,12 +54,9 @@ class Worker { }) const pipe = sp.stdio[3] pipe.on('error', (err) => { - if (pipe._readableState.ended && err.code === 'ENOTCONN') { - // this might happen during pipe destruction, ignore it since the pipe is closing soon, - // otherwise the main process will crash - } else { - throw err - } + if (err.code !== 'ENOTCONN') throw err + // 'ENOTCONN' might happen during pipe destruction, ignore it since the pipe is closing soon, + // otherwise the main process will crash }) pipe.on('end', () => pipe.end()) return pipe From ecfe16b750fd074b9234d6583978660d37f95f5b Mon Sep 17 00:00:00 2001 From: Marco Date: Sat, 23 Nov 2024 10:39:30 +1100 Subject: [PATCH 25/38] silent all errors --- lib/worker.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/worker.js b/lib/worker.js index d1edac412..30d2be6fc 100644 --- a/lib/worker.js +++ b/lib/worker.js @@ -54,9 +54,8 @@ class Worker { }) const pipe = sp.stdio[3] pipe.on('error', (err) => { - if (err.code !== 'ENOTCONN') throw err - // 'ENOTCONN' might happen during pipe destruction, ignore it since the pipe is closing soon, - // otherwise the main process will crash + // silent all errors here to avoid crashing the main process + // users can listen to 'error' event for custom error handling }) pipe.on('end', () => pipe.end()) return pipe From 4b70041c1a367407355b42f002278485ae0637db Mon Sep 17 00:00:00 2001 From: Marco Date: Sat, 23 Nov 2024 10:41:30 +1100 Subject: [PATCH 26/38] clean --- lib/worker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/worker.js b/lib/worker.js index 30d2be6fc..54b30f4fd 100644 --- a/lib/worker.js +++ b/lib/worker.js @@ -53,7 +53,7 @@ class Worker { this.#unref() }) const pipe = sp.stdio[3] - pipe.on('error', (err) => { + pipe.on('error', () => { // silent all errors here to avoid crashing the main process // users can listen to 'error' event for custom error handling }) From 8ac6cd221fe7802afd57650b49fbcd596b144572 Mon Sep 17 00:00:00 2001 From: Marco Date: Mon, 25 Nov 2024 19:34:08 +1100 Subject: [PATCH 27/38] override emit --- lib/worker.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/worker.js b/lib/worker.js index 54b30f4fd..2b5a5e72c 100644 --- a/lib/worker.js +++ b/lib/worker.js @@ -53,10 +53,12 @@ class Worker { this.#unref() }) const pipe = sp.stdio[3] - pipe.on('error', () => { - // silent all errors here to avoid crashing the main process - // users can listen to 'error' event for custom error handling - }) + pipe.pid = sp.pid + const pipeEmit = pipe.emit + pipe.emit = function (event, ...args) { + if (event === 'error' && args[0]?.code === 'ENOTCONN') return false + return pipeEmit.apply(this, [event, ...args]) + } pipe.on('end', () => pipe.end()) return pipe } From 630831cacf42b313b46487f6bd39ad08db3c57d9 Mon Sep 17 00:00:00 2001 From: Marco Date: Mon, 25 Nov 2024 21:13:35 +1100 Subject: [PATCH 28/38] add tests --- test/03-worker.test.js | 55 +++++++++++++++++++ test/fixtures/worker-child/index.js | 2 + test/fixtures/worker-child/package.json | 5 ++ .../worker-destroy-from-child/index.js | 4 ++ .../worker-destroy-from-child/package.json | 6 ++ .../worker-destroy-from-parent/index.js | 4 ++ .../worker-destroy-from-parent/package.json | 5 ++ test/fixtures/worker-end-from-child/index.js | 4 ++ .../worker-end-from-child/package.json | 6 ++ test/fixtures/worker-end-from-parent/index.js | 4 ++ .../worker-end-from-parent/package.json | 5 ++ test/fixtures/worker-parent/index.js | 4 ++ test/fixtures/worker-parent/package.json | 5 ++ test/helper.js | 16 ++++++ 14 files changed, 125 insertions(+) create mode 100644 test/fixtures/worker-child/index.js create mode 100644 test/fixtures/worker-child/package.json create mode 100644 test/fixtures/worker-destroy-from-child/index.js create mode 100644 test/fixtures/worker-destroy-from-child/package.json create mode 100644 test/fixtures/worker-destroy-from-parent/index.js create mode 100644 test/fixtures/worker-destroy-from-parent/package.json create mode 100644 test/fixtures/worker-end-from-child/index.js create mode 100644 test/fixtures/worker-end-from-child/package.json create mode 100644 test/fixtures/worker-end-from-parent/index.js create mode 100644 test/fixtures/worker-end-from-parent/package.json create mode 100644 test/fixtures/worker-parent/index.js create mode 100644 test/fixtures/worker-parent/package.json diff --git a/test/03-worker.test.js b/test/03-worker.test.js index 7a0972dcd..a2e344bd2 100644 --- a/test/03-worker.test.js +++ b/test/03-worker.test.js @@ -8,6 +8,13 @@ const helloWorld = path.join(Helper.localDir, 'test', 'fixtures', 'hello-world') const printArgs = path.join(Helper.localDir, 'test', 'fixtures', 'print-args') const workerRunner = path.join(Helper.localDir, 'test', 'fixtures', 'worker-runner') +const workerParent = path.join(Helper.localDir, 'test', 'fixtures', 'worker-parent') +const workerChild = path.join(Helper.localDir, 'test', 'fixtures', 'worker-child') +const workerEndFromChild = path.join(Helper.localDir, 'test', 'fixtures', 'worker-end-from-child') +const workerDestroyFromChild = path.join(Helper.localDir, 'test', 'fixtures', 'worker-destroy-from-child') +const workerEndFromParent = path.join(Helper.localDir, 'test', 'fixtures', 'worker-end-from-parent') +const workerDestroyFromParent = path.join(Helper.localDir, 'test', 'fixtures', 'worker-destroy-from-parent') + test('worker pipe', async function ({ is, plan, teardown }) { plan(1) const helper = new Helper() @@ -99,3 +106,51 @@ test('worker should run as a link in a terminal app', async function ({ is, plan await Helper.untilClose(pipe) }) + +// +// test worker exit gracefully for terminal app +// + +test('[terminal] worker exit when child calls pipe.end()', async function () { + const { pipe } = await Helper.run({ link: workerParent, args: [workerEndFromChild] }) + await Helper.untilClose(pipe) + await Helper.untilWorkerExit(pipe) +}) + +test('[terminal] worker exit when child calls pipe.destroy()', async function () { + const { pipe } = await Helper.run({ link: workerParent, args: [workerDestroyFromChild] }) + await Helper.untilClose(pipe) + await Helper.untilWorkerExit(pipe) +}) + +test.skip('[terminal] worker exit when parent calls pipe.end()', async function () { + const { pipe } = await Helper.run({ link: workerEndFromParent, args: [workerChild] }) + await Helper.untilClose(pipe) + await Helper.untilWorkerExit(pipe) +}) + +test.skip('[terminal] worker exit when parent calls pipe.destroy()', async function () { + const { pipe } = await Helper.run({ link: workerDestroyFromParent, args: [workerChild] }) + await Helper.untilClose(pipe) + await Helper.untilWorkerExit(pipe) +}) + +// +// test worker exit gracefully for desktop app +// + +test.skip('[desktop] worker exit when child calls pipe.end()', async function () { + +}) + +test.skip('[desktop] worker exit when child calls pipe.destroy()', async function () { + +}) + +test.skip('[desktop] worker exit when parent calls pipe.end()', async function () { + +}) + +test.skip('[desktop] worker exit when parent calls pipe.destroy()', async function () { + +}) diff --git a/test/fixtures/worker-child/index.js b/test/fixtures/worker-child/index.js new file mode 100644 index 000000000..8797b69bb --- /dev/null +++ b/test/fixtures/worker-child/index.js @@ -0,0 +1,2 @@ +const pipe = Pear.worker.pipe() +pipe.resume() diff --git a/test/fixtures/worker-child/package.json b/test/fixtures/worker-child/package.json new file mode 100644 index 000000000..4055ebd65 --- /dev/null +++ b/test/fixtures/worker-child/package.json @@ -0,0 +1,5 @@ +{ + "name": "worker-child", + "main": "index.js", + "pear": {} +} diff --git a/test/fixtures/worker-destroy-from-child/index.js b/test/fixtures/worker-destroy-from-child/index.js new file mode 100644 index 000000000..a8c644ac4 --- /dev/null +++ b/test/fixtures/worker-destroy-from-child/index.js @@ -0,0 +1,4 @@ +const pipe = Pear.worker.pipe() +pipe.resume() +await new Promise((resolve) => setTimeout(resolve, 1000)) +pipe.destroy() diff --git a/test/fixtures/worker-destroy-from-child/package.json b/test/fixtures/worker-destroy-from-child/package.json new file mode 100644 index 000000000..066b9a73e --- /dev/null +++ b/test/fixtures/worker-destroy-from-child/package.json @@ -0,0 +1,6 @@ +{ + "name": "worker-destroy-from-child", + "main": "index.js", + "type": "module", + "pear": {} +} diff --git a/test/fixtures/worker-destroy-from-parent/index.js b/test/fixtures/worker-destroy-from-parent/index.js new file mode 100644 index 000000000..a97d3c68f --- /dev/null +++ b/test/fixtures/worker-destroy-from-parent/index.js @@ -0,0 +1,4 @@ +const link = Bare.argv[Bare.argv.length - 1] +const pipe = Pear.worker.run(link) +pipe.resume() +pipe.destroy() diff --git a/test/fixtures/worker-destroy-from-parent/package.json b/test/fixtures/worker-destroy-from-parent/package.json new file mode 100644 index 000000000..fd73c6873 --- /dev/null +++ b/test/fixtures/worker-destroy-from-parent/package.json @@ -0,0 +1,5 @@ +{ + "name": "worker-destroy-from-parent", + "main": "index.js", + "pear": {} +} diff --git a/test/fixtures/worker-end-from-child/index.js b/test/fixtures/worker-end-from-child/index.js new file mode 100644 index 000000000..851aec84f --- /dev/null +++ b/test/fixtures/worker-end-from-child/index.js @@ -0,0 +1,4 @@ +const pipe = Pear.worker.pipe() +pipe.resume() +await new Promise((resolve) => setTimeout(resolve, 1000)) +pipe.end() diff --git a/test/fixtures/worker-end-from-child/package.json b/test/fixtures/worker-end-from-child/package.json new file mode 100644 index 000000000..baf2c411b --- /dev/null +++ b/test/fixtures/worker-end-from-child/package.json @@ -0,0 +1,6 @@ +{ + "name": "worker-end-from-child", + "main": "index.js", + "type": "module", + "pear": {} +} diff --git a/test/fixtures/worker-end-from-parent/index.js b/test/fixtures/worker-end-from-parent/index.js new file mode 100644 index 000000000..a96c94d17 --- /dev/null +++ b/test/fixtures/worker-end-from-parent/index.js @@ -0,0 +1,4 @@ +const link = Bare.argv[Bare.argv.length - 1] +const pipe = Pear.worker.run(link) +pipe.resume() +pipe.end() diff --git a/test/fixtures/worker-end-from-parent/package.json b/test/fixtures/worker-end-from-parent/package.json new file mode 100644 index 000000000..98383c314 --- /dev/null +++ b/test/fixtures/worker-end-from-parent/package.json @@ -0,0 +1,5 @@ +{ + "name": "worker-end-from-parent", + "main": "index.js", + "pear": {} +} diff --git a/test/fixtures/worker-parent/index.js b/test/fixtures/worker-parent/index.js new file mode 100644 index 000000000..b150cf5d0 --- /dev/null +++ b/test/fixtures/worker-parent/index.js @@ -0,0 +1,4 @@ + +const link = Bare.argv[Bare.argv.length - 1] +const pipe = Pear.worker.run(link) +pipe.resume() diff --git a/test/fixtures/worker-parent/package.json b/test/fixtures/worker-parent/package.json new file mode 100644 index 000000000..8926aba45 --- /dev/null +++ b/test/fixtures/worker-parent/package.json @@ -0,0 +1,5 @@ +{ + "name": "worker-parent", + "main": "index.js", + "pear": {} +} diff --git a/test/helper.js b/test/helper.js index 98766c021..0cefa9e5c 100644 --- a/test/helper.js +++ b/test/helper.js @@ -196,6 +196,22 @@ class Helper extends IPC.Client { return res } + static async isRunning (pipe) { + try { + return process.kill(pipe.pid, 0) + } catch (err) { + return err.code === 'EPERM' + } + } + + static async untilWorkerExit (pipe, timeout = 5000) { + const start = Date.now() + while (await this.isRunning(pipe)) { + if (Date.now() - start > timeout) throw new Error('timed out') + await new Promise((resolve) => setTimeout(resolve, 100)) + } + } + static async pick (stream, ptn = {}, by = 'tag') { if (Array.isArray(ptn)) return this.#untils(stream, ptn, by) for await (const output of stream) { From 791cadf366b24725fe129c27b875e2a343061b7f Mon Sep 17 00:00:00 2001 From: Marco Date: Mon, 25 Nov 2024 21:18:59 +1100 Subject: [PATCH 29/38] timeout --- test/fixtures/worker-destroy-from-parent/index.js | 1 + test/fixtures/worker-destroy-from-parent/package.json | 1 + test/fixtures/worker-end-from-parent/index.js | 1 + test/fixtures/worker-end-from-parent/package.json | 1 + test/fixtures/worker-parent/index.js | 1 - 5 files changed, 4 insertions(+), 1 deletion(-) diff --git a/test/fixtures/worker-destroy-from-parent/index.js b/test/fixtures/worker-destroy-from-parent/index.js index a97d3c68f..259ad675d 100644 --- a/test/fixtures/worker-destroy-from-parent/index.js +++ b/test/fixtures/worker-destroy-from-parent/index.js @@ -1,4 +1,5 @@ const link = Bare.argv[Bare.argv.length - 1] const pipe = Pear.worker.run(link) pipe.resume() +await new Promise((resolve) => setTimeout(resolve, 1000)) pipe.destroy() diff --git a/test/fixtures/worker-destroy-from-parent/package.json b/test/fixtures/worker-destroy-from-parent/package.json index fd73c6873..c445a4eef 100644 --- a/test/fixtures/worker-destroy-from-parent/package.json +++ b/test/fixtures/worker-destroy-from-parent/package.json @@ -1,5 +1,6 @@ { "name": "worker-destroy-from-parent", "main": "index.js", + "type": "module", "pear": {} } diff --git a/test/fixtures/worker-end-from-parent/index.js b/test/fixtures/worker-end-from-parent/index.js index a96c94d17..e1078c764 100644 --- a/test/fixtures/worker-end-from-parent/index.js +++ b/test/fixtures/worker-end-from-parent/index.js @@ -1,4 +1,5 @@ const link = Bare.argv[Bare.argv.length - 1] const pipe = Pear.worker.run(link) pipe.resume() +await new Promise((resolve) => setTimeout(resolve, 1000)) pipe.end() diff --git a/test/fixtures/worker-end-from-parent/package.json b/test/fixtures/worker-end-from-parent/package.json index 98383c314..f4025e15a 100644 --- a/test/fixtures/worker-end-from-parent/package.json +++ b/test/fixtures/worker-end-from-parent/package.json @@ -1,5 +1,6 @@ { "name": "worker-end-from-parent", "main": "index.js", + "type": "module", "pear": {} } diff --git a/test/fixtures/worker-parent/index.js b/test/fixtures/worker-parent/index.js index b150cf5d0..f0edda3c5 100644 --- a/test/fixtures/worker-parent/index.js +++ b/test/fixtures/worker-parent/index.js @@ -1,4 +1,3 @@ - const link = Bare.argv[Bare.argv.length - 1] const pipe = Pear.worker.run(link) pipe.resume() From dab25b825c99c10180c7008032f64fb9a8a893fe Mon Sep 17 00:00:00 2001 From: Marco Date: Mon, 25 Nov 2024 21:20:02 +1100 Subject: [PATCH 30/38] test terminal app ok --- test/03-worker.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/03-worker.test.js b/test/03-worker.test.js index a2e344bd2..87fb9d7fb 100644 --- a/test/03-worker.test.js +++ b/test/03-worker.test.js @@ -123,13 +123,13 @@ test('[terminal] worker exit when child calls pipe.destroy()', async function () await Helper.untilWorkerExit(pipe) }) -test.skip('[terminal] worker exit when parent calls pipe.end()', async function () { +test('[terminal] worker exit when parent calls pipe.end()', async function () { const { pipe } = await Helper.run({ link: workerEndFromParent, args: [workerChild] }) await Helper.untilClose(pipe) await Helper.untilWorkerExit(pipe) }) -test.skip('[terminal] worker exit when parent calls pipe.destroy()', async function () { +test('[terminal] worker exit when parent calls pipe.destroy()', async function () { const { pipe } = await Helper.run({ link: workerDestroyFromParent, args: [workerChild] }) await Helper.untilClose(pipe) await Helper.untilWorkerExit(pipe) From c2600d43cd49dbe70e1e7b1865f0821155352ac3 Mon Sep 17 00:00:00 2001 From: Marco Date: Mon, 25 Nov 2024 21:45:33 +1100 Subject: [PATCH 31/38] terminal test ok --- gui/preload.js | 4 ++-- test/03-worker.test.js | 5 +---- test/fixtures/worker-child/package.json | 1 + .../worker-destroy-from-parent/index.js | 17 +++++++++++++++++ test/fixtures/worker-end-from-parent/index.js | 17 +++++++++++++++++ test/fixtures/worker-parent/index.js | 17 +++++++++++++++++ test/fixtures/worker-parent/package.json | 1 + test/helper.js | 16 ---------------- 8 files changed, 56 insertions(+), 22 deletions(-) diff --git a/gui/preload.js b/gui/preload.js index 84c677549..38c91bae4 100644 --- a/gui/preload.js +++ b/gui/preload.js @@ -295,9 +295,9 @@ class IPC { return stream } - workerRun (link) { + workerRun (link, args) { const id = electron.ipcRenderer.sendSync('workerPipeId') - electron.ipcRenderer.send('workerRun', link) + electron.ipcRenderer.send('workerRun', link, args) const stream = new streamx.Duplex({ write (data, cb) { electron.ipcRenderer.send('workerPipeWrite', id, data) diff --git a/test/03-worker.test.js b/test/03-worker.test.js index 87fb9d7fb..da98cc2f6 100644 --- a/test/03-worker.test.js +++ b/test/03-worker.test.js @@ -14,6 +14,7 @@ const workerEndFromChild = path.join(Helper.localDir, 'test', 'fixtures', 'worke const workerDestroyFromChild = path.join(Helper.localDir, 'test', 'fixtures', 'worker-destroy-from-child') const workerEndFromParent = path.join(Helper.localDir, 'test', 'fixtures', 'worker-end-from-parent') const workerDestroyFromParent = path.join(Helper.localDir, 'test', 'fixtures', 'worker-destroy-from-parent') +const workerParentDesktop = path.join(Helper.localDir, 'test', 'fixtures', 'worker-parent-desktop') test('worker pipe', async function ({ is, plan, teardown }) { plan(1) @@ -114,25 +115,21 @@ test('worker should run as a link in a terminal app', async function ({ is, plan test('[terminal] worker exit when child calls pipe.end()', async function () { const { pipe } = await Helper.run({ link: workerParent, args: [workerEndFromChild] }) await Helper.untilClose(pipe) - await Helper.untilWorkerExit(pipe) }) test('[terminal] worker exit when child calls pipe.destroy()', async function () { const { pipe } = await Helper.run({ link: workerParent, args: [workerDestroyFromChild] }) await Helper.untilClose(pipe) - await Helper.untilWorkerExit(pipe) }) test('[terminal] worker exit when parent calls pipe.end()', async function () { const { pipe } = await Helper.run({ link: workerEndFromParent, args: [workerChild] }) await Helper.untilClose(pipe) - await Helper.untilWorkerExit(pipe) }) test('[terminal] worker exit when parent calls pipe.destroy()', async function () { const { pipe } = await Helper.run({ link: workerDestroyFromParent, args: [workerChild] }) await Helper.untilClose(pipe) - await Helper.untilWorkerExit(pipe) }) // diff --git a/test/fixtures/worker-child/package.json b/test/fixtures/worker-child/package.json index 4055ebd65..427f3c568 100644 --- a/test/fixtures/worker-child/package.json +++ b/test/fixtures/worker-child/package.json @@ -1,5 +1,6 @@ { "name": "worker-child", "main": "index.js", + "type": "module", "pear": {} } diff --git a/test/fixtures/worker-destroy-from-parent/index.js b/test/fixtures/worker-destroy-from-parent/index.js index 259ad675d..b06188b2b 100644 --- a/test/fixtures/worker-destroy-from-parent/index.js +++ b/test/fixtures/worker-destroy-from-parent/index.js @@ -3,3 +3,20 @@ const pipe = Pear.worker.run(link) pipe.resume() await new Promise((resolve) => setTimeout(resolve, 1000)) pipe.destroy() +await untilExit(pipe) + +async function untilExit (pipe, timeout = 5000) { + const start = Date.now() + while (isRunning(pipe)) { + if (Date.now() - start > timeout) throw new Error('timed out') + await new Promise((resolve) => setTimeout(resolve, 100)) + } +} + +function isRunning (pipe) { + try { + return process.kill(pipe.pid, 0) + } catch (err) { + return err.code === 'EPERM' + } +} diff --git a/test/fixtures/worker-end-from-parent/index.js b/test/fixtures/worker-end-from-parent/index.js index e1078c764..420be2fe2 100644 --- a/test/fixtures/worker-end-from-parent/index.js +++ b/test/fixtures/worker-end-from-parent/index.js @@ -3,3 +3,20 @@ const pipe = Pear.worker.run(link) pipe.resume() await new Promise((resolve) => setTimeout(resolve, 1000)) pipe.end() +await untilExit(pipe) + +async function untilExit (pipe, timeout = 5000) { + const start = Date.now() + while (isRunning(pipe)) { + if (Date.now() - start > timeout) throw new Error('timed out') + await new Promise((resolve) => setTimeout(resolve, 100)) + } +} + +function isRunning (pipe) { + try { + return process.kill(pipe.pid, 0) + } catch (err) { + return err.code === 'EPERM' + } +} diff --git a/test/fixtures/worker-parent/index.js b/test/fixtures/worker-parent/index.js index f0edda3c5..12976e15f 100644 --- a/test/fixtures/worker-parent/index.js +++ b/test/fixtures/worker-parent/index.js @@ -1,3 +1,20 @@ const link = Bare.argv[Bare.argv.length - 1] const pipe = Pear.worker.run(link) pipe.resume() +await untilExit(pipe) + +async function untilExit (pipe, timeout = 5000) { + const start = Date.now() + while (isRunning(pipe)) { + if (Date.now() - start > timeout) throw new Error('timed out') + await new Promise((resolve) => setTimeout(resolve, 100)) + } +} + +function isRunning (pipe) { + try { + return process.kill(pipe.pid, 0) + } catch (err) { + return err.code === 'EPERM' + } +} diff --git a/test/fixtures/worker-parent/package.json b/test/fixtures/worker-parent/package.json index 8926aba45..4114340f2 100644 --- a/test/fixtures/worker-parent/package.json +++ b/test/fixtures/worker-parent/package.json @@ -1,5 +1,6 @@ { "name": "worker-parent", "main": "index.js", + "type": "module", "pear": {} } diff --git a/test/helper.js b/test/helper.js index 0cefa9e5c..98766c021 100644 --- a/test/helper.js +++ b/test/helper.js @@ -196,22 +196,6 @@ class Helper extends IPC.Client { return res } - static async isRunning (pipe) { - try { - return process.kill(pipe.pid, 0) - } catch (err) { - return err.code === 'EPERM' - } - } - - static async untilWorkerExit (pipe, timeout = 5000) { - const start = Date.now() - while (await this.isRunning(pipe)) { - if (Date.now() - start > timeout) throw new Error('timed out') - await new Promise((resolve) => setTimeout(resolve, 100)) - } - } - static async pick (stream, ptn = {}, by = 'tag') { if (Array.isArray(ptn)) return this.#untils(stream, ptn, by) for await (const output of stream) { From cc0df15491348c3bc4b8c09e854d1a7353b63e21 Mon Sep 17 00:00:00 2001 From: Marco Date: Mon, 25 Nov 2024 21:49:54 +1100 Subject: [PATCH 32/38] test desktop --- test/03-worker.test.js | 5 ++-- test/fixtures/worker-parent-desktop/app.js | 24 +++++++++++++++++++ .../fixtures/worker-parent-desktop/index.html | 2 ++ .../worker-parent-desktop/package.json | 6 +++++ 4 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 test/fixtures/worker-parent-desktop/app.js create mode 100644 test/fixtures/worker-parent-desktop/index.html create mode 100644 test/fixtures/worker-parent-desktop/package.json diff --git a/test/03-worker.test.js b/test/03-worker.test.js index da98cc2f6..f13b95cf4 100644 --- a/test/03-worker.test.js +++ b/test/03-worker.test.js @@ -136,8 +136,9 @@ test('[terminal] worker exit when parent calls pipe.destroy()', async function ( // test worker exit gracefully for desktop app // -test.skip('[desktop] worker exit when child calls pipe.end()', async function () { - +test('[desktop] worker exit when child calls pipe.end()', async function () { + const { pipe } = await Helper.run({ link: workerParentDesktop, args: [workerChild] }) + await Helper.untilClose(pipe) }) test.skip('[desktop] worker exit when child calls pipe.destroy()', async function () { diff --git a/test/fixtures/worker-parent-desktop/app.js b/test/fixtures/worker-parent-desktop/app.js new file mode 100644 index 000000000..d9f0c4f17 --- /dev/null +++ b/test/fixtures/worker-parent-desktop/app.js @@ -0,0 +1,24 @@ +const pipeIn = Pear.worker.pipe() +const link = Pear.config.args[Pear.config.args.length - 1] +const pipe = Pear.worker.run(link) +pipe.resume() +await new Promise((resolve) => setTimeout(resolve, 1000)) +pipe.end() +await untilExit(pipe) +Pear.Window.self.close() + +async function untilExit (pipe, timeout = 5000) { + const start = Date.now() + while (isRunning(pipe)) { + if (Date.now() - start > timeout) throw new Error('timed out') + await new Promise((resolve) => setTimeout(resolve, 100)) + } +} + +function isRunning (pipe) { + try { + return process.kill(pipe.pid, 0) + } catch (err) { + return err.code === 'EPERM' + } +} diff --git a/test/fixtures/worker-parent-desktop/index.html b/test/fixtures/worker-parent-desktop/index.html new file mode 100644 index 000000000..91a294a71 --- /dev/null +++ b/test/fixtures/worker-parent-desktop/index.html @@ -0,0 +1,2 @@ + + diff --git a/test/fixtures/worker-parent-desktop/package.json b/test/fixtures/worker-parent-desktop/package.json new file mode 100644 index 000000000..f08d57e18 --- /dev/null +++ b/test/fixtures/worker-parent-desktop/package.json @@ -0,0 +1,6 @@ +{ + "name": "worker-parent-desktop", + "main": "index.html", + "type": "module", + "pear": {} +} From ca500fbf588146dd9f6f71510b8ec30d657461a6 Mon Sep 17 00:00:00 2001 From: Marco Date: Mon, 25 Nov 2024 21:52:26 +1100 Subject: [PATCH 33/38] ok --- test/fixtures/worker-parent-desktop/app.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/fixtures/worker-parent-desktop/app.js b/test/fixtures/worker-parent-desktop/app.js index d9f0c4f17..3a66fa520 100644 --- a/test/fixtures/worker-parent-desktop/app.js +++ b/test/fixtures/worker-parent-desktop/app.js @@ -2,8 +2,6 @@ const pipeIn = Pear.worker.pipe() const link = Pear.config.args[Pear.config.args.length - 1] const pipe = Pear.worker.run(link) pipe.resume() -await new Promise((resolve) => setTimeout(resolve, 1000)) -pipe.end() await untilExit(pipe) Pear.Window.self.close() From 0cbb43e924a16cfaa2e184437ef5866a2dfee441 Mon Sep 17 00:00:00 2001 From: Marco Date: Mon, 25 Nov 2024 21:53:29 +1100 Subject: [PATCH 34/38] all tests --- .../worker-destroy-from-parent-desktop/app.js | 24 +++++++++++++++++++ .../index.html | 2 ++ .../package.json | 6 +++++ .../worker-end-from-parent-desktop/app.js | 24 +++++++++++++++++++ .../worker-end-from-parent-desktop/index.html | 2 ++ .../package.json | 6 +++++ 6 files changed, 64 insertions(+) create mode 100644 test/fixtures/worker-destroy-from-parent-desktop/app.js create mode 100644 test/fixtures/worker-destroy-from-parent-desktop/index.html create mode 100644 test/fixtures/worker-destroy-from-parent-desktop/package.json create mode 100644 test/fixtures/worker-end-from-parent-desktop/app.js create mode 100644 test/fixtures/worker-end-from-parent-desktop/index.html create mode 100644 test/fixtures/worker-end-from-parent-desktop/package.json diff --git a/test/fixtures/worker-destroy-from-parent-desktop/app.js b/test/fixtures/worker-destroy-from-parent-desktop/app.js new file mode 100644 index 000000000..515b73c69 --- /dev/null +++ b/test/fixtures/worker-destroy-from-parent-desktop/app.js @@ -0,0 +1,24 @@ +const pipeIn = Pear.worker.pipe() +const link = Pear.config.args[Pear.config.args.length - 1] +const pipe = Pear.worker.run(link) +pipe.resume() +await new Promise((resolve) => setTimeout(resolve, 1000)) +pipe.destroy() +await untilExit(pipe) +Pear.Window.self.close() + +async function untilExit (pipe, timeout = 5000) { + const start = Date.now() + while (isRunning(pipe)) { + if (Date.now() - start > timeout) throw new Error('timed out') + await new Promise((resolve) => setTimeout(resolve, 100)) + } +} + +function isRunning (pipe) { + try { + return process.kill(pipe.pid, 0) + } catch (err) { + return err.code === 'EPERM' + } +} diff --git a/test/fixtures/worker-destroy-from-parent-desktop/index.html b/test/fixtures/worker-destroy-from-parent-desktop/index.html new file mode 100644 index 000000000..91a294a71 --- /dev/null +++ b/test/fixtures/worker-destroy-from-parent-desktop/index.html @@ -0,0 +1,2 @@ + + diff --git a/test/fixtures/worker-destroy-from-parent-desktop/package.json b/test/fixtures/worker-destroy-from-parent-desktop/package.json new file mode 100644 index 000000000..f08d57e18 --- /dev/null +++ b/test/fixtures/worker-destroy-from-parent-desktop/package.json @@ -0,0 +1,6 @@ +{ + "name": "worker-parent-desktop", + "main": "index.html", + "type": "module", + "pear": {} +} diff --git a/test/fixtures/worker-end-from-parent-desktop/app.js b/test/fixtures/worker-end-from-parent-desktop/app.js new file mode 100644 index 000000000..d9f0c4f17 --- /dev/null +++ b/test/fixtures/worker-end-from-parent-desktop/app.js @@ -0,0 +1,24 @@ +const pipeIn = Pear.worker.pipe() +const link = Pear.config.args[Pear.config.args.length - 1] +const pipe = Pear.worker.run(link) +pipe.resume() +await new Promise((resolve) => setTimeout(resolve, 1000)) +pipe.end() +await untilExit(pipe) +Pear.Window.self.close() + +async function untilExit (pipe, timeout = 5000) { + const start = Date.now() + while (isRunning(pipe)) { + if (Date.now() - start > timeout) throw new Error('timed out') + await new Promise((resolve) => setTimeout(resolve, 100)) + } +} + +function isRunning (pipe) { + try { + return process.kill(pipe.pid, 0) + } catch (err) { + return err.code === 'EPERM' + } +} diff --git a/test/fixtures/worker-end-from-parent-desktop/index.html b/test/fixtures/worker-end-from-parent-desktop/index.html new file mode 100644 index 000000000..91a294a71 --- /dev/null +++ b/test/fixtures/worker-end-from-parent-desktop/index.html @@ -0,0 +1,2 @@ + + diff --git a/test/fixtures/worker-end-from-parent-desktop/package.json b/test/fixtures/worker-end-from-parent-desktop/package.json new file mode 100644 index 000000000..f08d57e18 --- /dev/null +++ b/test/fixtures/worker-end-from-parent-desktop/package.json @@ -0,0 +1,6 @@ +{ + "name": "worker-parent-desktop", + "main": "index.html", + "type": "module", + "pear": {} +} From a376e600db63580aa94bb9b1d027af483ff731f2 Mon Sep 17 00:00:00 2001 From: Marco Date: Mon, 25 Nov 2024 21:54:05 +1100 Subject: [PATCH 35/38] name --- test/fixtures/worker-destroy-from-parent-desktop/package.json | 2 +- test/fixtures/worker-end-from-parent-desktop/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/fixtures/worker-destroy-from-parent-desktop/package.json b/test/fixtures/worker-destroy-from-parent-desktop/package.json index f08d57e18..5abd6a4ee 100644 --- a/test/fixtures/worker-destroy-from-parent-desktop/package.json +++ b/test/fixtures/worker-destroy-from-parent-desktop/package.json @@ -1,5 +1,5 @@ { - "name": "worker-parent-desktop", + "name": "worker-destroy-from-parent-desktop", "main": "index.html", "type": "module", "pear": {} diff --git a/test/fixtures/worker-end-from-parent-desktop/package.json b/test/fixtures/worker-end-from-parent-desktop/package.json index f08d57e18..bb61de6d0 100644 --- a/test/fixtures/worker-end-from-parent-desktop/package.json +++ b/test/fixtures/worker-end-from-parent-desktop/package.json @@ -1,5 +1,5 @@ { - "name": "worker-parent-desktop", + "name": "worker-end-from-parent-desktop", "main": "index.html", "type": "module", "pear": {} From b3dbcb57a4210c2384362a976fa0aa2d11e8b860 Mon Sep 17 00:00:00 2001 From: Marco Date: Mon, 25 Nov 2024 21:54:24 +1100 Subject: [PATCH 36/38] test --- test/03-worker.test.js | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/test/03-worker.test.js b/test/03-worker.test.js index f13b95cf4..06b38faba 100644 --- a/test/03-worker.test.js +++ b/test/03-worker.test.js @@ -14,7 +14,10 @@ const workerEndFromChild = path.join(Helper.localDir, 'test', 'fixtures', 'worke const workerDestroyFromChild = path.join(Helper.localDir, 'test', 'fixtures', 'worker-destroy-from-child') const workerEndFromParent = path.join(Helper.localDir, 'test', 'fixtures', 'worker-end-from-parent') const workerDestroyFromParent = path.join(Helper.localDir, 'test', 'fixtures', 'worker-destroy-from-parent') + const workerParentDesktop = path.join(Helper.localDir, 'test', 'fixtures', 'worker-parent-desktop') +const workerEndFromParentDesktop = path.join(Helper.localDir, 'test', 'fixtures', 'worker-end-from-parent-desktop') +const workerDestroyFromParentDesktop = path.join(Helper.localDir, 'test', 'fixtures', 'worker-destroy-from-parent-desktop') test('worker pipe', async function ({ is, plan, teardown }) { plan(1) @@ -137,18 +140,21 @@ test('[terminal] worker exit when parent calls pipe.destroy()', async function ( // test('[desktop] worker exit when child calls pipe.end()', async function () { - const { pipe } = await Helper.run({ link: workerParentDesktop, args: [workerChild] }) + const { pipe } = await Helper.run({ link: workerParentDesktop, args: [workerEndFromChild] }) await Helper.untilClose(pipe) }) -test.skip('[desktop] worker exit when child calls pipe.destroy()', async function () { - +test('[desktop] worker exit when child calls pipe.destroy()', async function () { + const { pipe } = await Helper.run({ link: workerParentDesktop, args: [workerDestroyFromChild] }) + await Helper.untilClose(pipe) }) -test.skip('[desktop] worker exit when parent calls pipe.end()', async function () { - +test('[desktop] worker exit when parent calls pipe.end()', async function () { + const { pipe } = await Helper.run({ link: workerEndFromParentDesktop, args: [workerChild] }) + await Helper.untilClose(pipe) }) -test.skip('[desktop] worker exit when parent calls pipe.destroy()', async function () { - +test('[desktop] worker exit when parent calls pipe.destroy()', async function () { + const { pipe } = await Helper.run({ link: workerDestroyFromParentDesktop, args: [workerChild] }) + await Helper.untilClose(pipe) }) From d1275201de5952131a17d268278e41a6df471c0c Mon Sep 17 00:00:00 2001 From: Marco Date: Mon, 25 Nov 2024 22:13:46 +1100 Subject: [PATCH 37/38] desktop tests ok --- test/03-worker.test.js | 16 ++++++++-------- test/helper.js | 16 ++++++++++++++++ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/test/03-worker.test.js b/test/03-worker.test.js index 06b38faba..8c8467ff8 100644 --- a/test/03-worker.test.js +++ b/test/03-worker.test.js @@ -117,22 +117,22 @@ test('worker should run as a link in a terminal app', async function ({ is, plan test('[terminal] worker exit when child calls pipe.end()', async function () { const { pipe } = await Helper.run({ link: workerParent, args: [workerEndFromChild] }) - await Helper.untilClose(pipe) + await Helper.untilWorkerExit(pipe) }) test('[terminal] worker exit when child calls pipe.destroy()', async function () { const { pipe } = await Helper.run({ link: workerParent, args: [workerDestroyFromChild] }) - await Helper.untilClose(pipe) + await Helper.untilWorkerExit(pipe) }) test('[terminal] worker exit when parent calls pipe.end()', async function () { const { pipe } = await Helper.run({ link: workerEndFromParent, args: [workerChild] }) - await Helper.untilClose(pipe) + await Helper.untilWorkerExit(pipe) }) test('[terminal] worker exit when parent calls pipe.destroy()', async function () { const { pipe } = await Helper.run({ link: workerDestroyFromParent, args: [workerChild] }) - await Helper.untilClose(pipe) + await Helper.untilWorkerExit(pipe) }) // @@ -141,20 +141,20 @@ test('[terminal] worker exit when parent calls pipe.destroy()', async function ( test('[desktop] worker exit when child calls pipe.end()', async function () { const { pipe } = await Helper.run({ link: workerParentDesktop, args: [workerEndFromChild] }) - await Helper.untilClose(pipe) + await Helper.untilWorkerExit(pipe) }) test('[desktop] worker exit when child calls pipe.destroy()', async function () { const { pipe } = await Helper.run({ link: workerParentDesktop, args: [workerDestroyFromChild] }) - await Helper.untilClose(pipe) + await Helper.untilWorkerExit(pipe) }) test('[desktop] worker exit when parent calls pipe.end()', async function () { const { pipe } = await Helper.run({ link: workerEndFromParentDesktop, args: [workerChild] }) - await Helper.untilClose(pipe) + await Helper.untilWorkerExit(pipe) }) test('[desktop] worker exit when parent calls pipe.destroy()', async function () { const { pipe } = await Helper.run({ link: workerDestroyFromParentDesktop, args: [workerChild] }) - await Helper.untilClose(pipe) + await Helper.untilWorkerExit(pipe) }) diff --git a/test/helper.js b/test/helper.js index 98766c021..0cefa9e5c 100644 --- a/test/helper.js +++ b/test/helper.js @@ -196,6 +196,22 @@ class Helper extends IPC.Client { return res } + static async isRunning (pipe) { + try { + return process.kill(pipe.pid, 0) + } catch (err) { + return err.code === 'EPERM' + } + } + + static async untilWorkerExit (pipe, timeout = 5000) { + const start = Date.now() + while (await this.isRunning(pipe)) { + if (Date.now() - start > timeout) throw new Error('timed out') + await new Promise((resolve) => setTimeout(resolve, 100)) + } + } + static async pick (stream, ptn = {}, by = 'tag') { if (Array.isArray(ptn)) return this.#untils(stream, ptn, by) for await (const output of stream) { From 875105e53c7ae6fdabd54de68bcc61e72feae495 Mon Sep 17 00:00:00 2001 From: Marco Date: Mon, 25 Nov 2024 22:14:46 +1100 Subject: [PATCH 38/38] clean --- test/fixtures/worker-destroy-from-parent-desktop/app.js | 1 - test/fixtures/worker-end-from-parent-desktop/app.js | 1 - test/fixtures/worker-parent-desktop/app.js | 1 - 3 files changed, 3 deletions(-) diff --git a/test/fixtures/worker-destroy-from-parent-desktop/app.js b/test/fixtures/worker-destroy-from-parent-desktop/app.js index 515b73c69..fb22b5e91 100644 --- a/test/fixtures/worker-destroy-from-parent-desktop/app.js +++ b/test/fixtures/worker-destroy-from-parent-desktop/app.js @@ -1,4 +1,3 @@ -const pipeIn = Pear.worker.pipe() const link = Pear.config.args[Pear.config.args.length - 1] const pipe = Pear.worker.run(link) pipe.resume() diff --git a/test/fixtures/worker-end-from-parent-desktop/app.js b/test/fixtures/worker-end-from-parent-desktop/app.js index d9f0c4f17..5782bd3c1 100644 --- a/test/fixtures/worker-end-from-parent-desktop/app.js +++ b/test/fixtures/worker-end-from-parent-desktop/app.js @@ -1,4 +1,3 @@ -const pipeIn = Pear.worker.pipe() const link = Pear.config.args[Pear.config.args.length - 1] const pipe = Pear.worker.run(link) pipe.resume() diff --git a/test/fixtures/worker-parent-desktop/app.js b/test/fixtures/worker-parent-desktop/app.js index 3a66fa520..1589e0bfc 100644 --- a/test/fixtures/worker-parent-desktop/app.js +++ b/test/fixtures/worker-parent-desktop/app.js @@ -1,4 +1,3 @@ -const pipeIn = Pear.worker.pipe() const link = Pear.config.args[Pear.config.args.length - 1] const pipe = Pear.worker.run(link) pipe.resume()