Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stopping a node.js program with SIGINT while esbuild watch is running sometimes causes EPIPE error #2007

Closed
AlCalzone opened this issue Feb 10, 2022 · 5 comments

Comments

@AlCalzone
Copy link

I have a Node.js program that uses esbuild's watch mode to compile React TSX files. In this program, i listen for the SIGINT signal to shut down the watch process gracefully:

	const buildProcess = await build({
	    // These are the remaining build options
		...getReactBuildOptions(entryPoints, tsConfigPath),

		watch: true,
	});

	process.on("SIGINT", () => {
		console.log();
		console.log("SIGINT received, shutting down...");
		buildProcess.stop?.();
	});

However most of the time, I'm getting this error instead:

node:events:368
      throw er; // Unhandled 'error' event
      ^

Error: write EPIPE
    at afterWriteDispatched (node:internal/stream_base_commons:164:15)
    at writeGeneric (node:internal/stream_base_commons:155:3)
    at Socket._writeGeneric (node:net:780:11)
    at Socket._write (node:net:792:8)
    at writeOrBuffer (node:internal/streams/writable:389:12)
    at _write (node:internal/streams/writable:330:10)
    at Socket.Writable.write (node:internal/streams/writable:334:10)
    at Object.writeToStdin (C:\Repositories\adapter-dev\node_modules\esbuild\lib\main.js:2027:19)
    at sendRequest (C:\Repositories\adapter-dev\node_modules\esbuild\lib\main.js:672:14)
    at Object.stop (C:\Repositories\adapter-dev\node_modules\esbuild\lib\main.js:1289:15)
Emitted 'error' event on Socket instance at:
    at emitErrorNT (node:internal/streams/destroy:157:8)
    at emitErrorCloseNT (node:internal/streams/destroy:122:3)
    at processTicksAndRejections (node:internal/process/task_queues:83:21) {
  errno: -4047,
  code: 'EPIPE',
  syscall: 'write'
}

It seems that the child process that esbuild starts, gets killed by the SIGINT before stop gets called.

@evanw
Copy link
Owner

evanw commented Feb 16, 2022

I figured out how to reproduce this. This doesn't even require watch mode to be enabled. You can reproduce this with a simple plugin that just builds infinitely:

process.on("SIGINT", () => console.log('SIGINT'))
esbuild.build({
  stdin: { contents: `import 'x'` },
  bundle: true,
  plugins: [{
    name: 'infinity',
    setup(build) {
      build.onResolve({ filter: /.*/ }, args => ({ path: args.path, namespace: 'x' }))
      build.onLoad({ filter: /.*/ }, args => ({
        contents: `
          import 'a${args.path}'
          import 'b${args.path}'
        `,
      }))
    },
  }],
}).catch(e => console.error('caught ' + e))

It looks like maybe this happens because I'm not passing a callback to the stdin.write function.

@evanw evanw closed this as completed in 0af35be Feb 16, 2022
@nemphys
Copy link

nemphys commented May 11, 2022

@evanw I am facing the same issue, but on a web service that serves scripts minified by esbuild.

Since I already have a graceful shutdown procedure in place, which kindly waits for the various components of the application to shut down taking their time, I am wondering if we could have some way of letting esbuild do its thing, (conditionally) ignoring the SIGINT signal.

Right now (though this commit is an improvement), all we get is a failed build.

@evanw
Copy link
Owner

evanw commented May 11, 2022

The issue you are commenting on was closed because it has been fixed. If you want the fix, please update your version of esbuild to one that has the fix. Or, if your issue is different than this one, please file a new issue and include a way to demonstrate your problem so it can be fixed too.

@evanw
Copy link
Owner

evanw commented May 11, 2022

Sorry, I just re-read the last sentence. I think you're asking for esbuild to not fail the build if the data from its child process is cut off? That doesn't sound like a good idea to me since it could mask all kinds of legitimate issues. Why not just ignore build failures from esbuild if your graceful shutdown procedure is in progress?

@nemphys
Copy link

nemphys commented May 11, 2022

Yes, that is what I am currently doing.

I used the word "conditionally", since maybe we could have some special handler (eg through some kind of init option) that could signify this specific case.

But now that I think about it, the child process should ignore the SIGINT signal (so that it does not stop doing its job), which I suppose is not possible, right?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants