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

Support process.on("unhandledRejection") and process.on("uncaughtException") #429

Closed
borkdude opened this issue Jul 8, 2022 · 24 comments · Fixed by #10902
Closed

Support process.on("unhandledRejection") and process.on("uncaughtException") #429

borkdude opened this issue Jul 8, 2022 · 24 comments · Fixed by #10902
Labels
atw enhancement New feature or request node.js Compatibility with Node.js APIs

Comments

@borkdude
Copy link

borkdude commented Jul 8, 2022

Repro:

process.on(
  "unhandledRejection",
  (err) => {
    console.log('error' + err);
  });

const foo = new Promise((resolve,reject) => {
  setTimeout(() => {
    reject('foo');
  }, 300);
});

Error:

$ bun run /tmp/process.js
[1.16ms] "node_modules.bun" - 105 modules, 46 packages
1 | process.on("unhandledRejection", (err) => {
  console.log("error" + err);
});
   ^
 TypeError: process.on is not a function. (In 'process.on("unhandledRejection", (err) => {
  console.log("error" + err);
})', 'process.on' is undefined)
      at /private/tmp/process.js:1:0
@Jarred-Sumner Jarred-Sumner added bug Something isn't working node.js Compatibility with Node.js APIs labels Jul 8, 2022
@Shubhcs01
Copy link

hello sir, I want to work on this issue. Can you please guide me to where I can find this code inside the project?

@xHyroM xHyroM added enhancement New feature or request polyfill and removed bug Something isn't working enhancement New feature or request labels Jul 28, 2022
@Jarred-Sumner
Copy link
Collaborator

Small update

process.on technically works but it does not monitor the events as expected, it just extends from EventEmitter. I am keeping this issue open because that doesn't fully address the intended issue

@borkdude
Copy link
Author

Thanks! At least nbb doesn't trip over that anymore: https://twitter.com/borkdude/status/1581582447661449216

The remaining issues in nbb to have a REPL are "readline" and "vm" support.

@chrisdavies
Copy link

I'm interested in gracefully handling process exit. Right now, I noticed that some SQLite data fails to persist unless the database is gracefully closed. I'd like to do something like this:

process.on('beforeExit', () => db.close());

The SQL behavior probably warrants its own top-level issue, I suppose.

@dror-weiss
Copy link

This feature is much needed; any progress on this?

@W2Wizard
Copy link

Would really love if this got implemented!

@Jarred-Sumner
Copy link
Collaborator

I'm interested in gracefully handling process exit. Right now, I noticed that some SQLite data fails to persist unless the database is gracefully closed. I'd like to do something like this:

process.on('beforeExit', () => db.close());

The SQL behavior probably warrants its own top-level issue, I suppose.

This has been fixed in canary (and will land in Bun v0.6.14)

@Jarred-Sumner
Copy link
Collaborator

beforeExit, exit have both landed in canary as well and tomorrow signal handlers will too.

unhandledRejection will not land in this canary

@baptistecs
Copy link

Hello,

// @ts-ignore
process.on('beforeExit', () => console.log('beforeExit'));
// @ts-ignore
process.on('exit', () => console.log('exit'));

// without ts-ignore, we get "Property 'on' does not exist on type 'Process'.ts(2339)"

None of them are called in 0.7.0 after pressing CTRL+C, is that expected?

@Jarred-Sumner
Copy link
Collaborator

Jarred-Sumner commented Jul 26, 2023

None of them are called in 0.7.0 after pressing CTRL+C, is that expected?

Yes, that is consistent with Node.js:

image

@maxmilton
Copy link
Contributor

maxmilton commented Jul 27, 2023

@baptistecs normally CTRL+C is intercepted by your terminal tty driver and it usually sends an interrupt signal (SIGINT). You could do something like:

process.on('SIGINT', ...);

I often use it for closing a database connection when exiting the sever process like so (as in the better-sqlite3 docs):

process.on('exit', () => db.close());
process.on('SIGHUP', () => process.exit(128 + 1)); // hang up
process.on('SIGINT', () => process.exit(128 + 2)); // ctrl+c
process.on('SIGTERM', () => process.exit(128 + 15)); // kill

Although I'm not sure it works in bun yet. The process.on() handlers should get called, so see if it works for you.

@baptistecs
Copy link

Thank you @maxmilton!

I confirm, this is working:

process.on("SIGINT", () => {
    console.log('EXIT');
    process.exit(0);
});

@Electroid Electroid changed the title Node.js process.on compatibility Support process.on("unhandledRejection") Oct 24, 2023
@Electroid Electroid added the enhancement New feature or request label Oct 24, 2023
@DeniroBlack
Copy link

DeniroBlack commented Jan 6, 2024

Unfortunately, this will not be fixed by bun.js is not suitable for large projects, because without these signals it is impossible to make a normal error handler 😔

Please add unhandledRejection and uncaughtException I'll be waiting. Until then, I will use Bun only as a package manager.

@Electroid Electroid changed the title Support process.on("unhandledRejection") Support process.on("unhandledRejection") and process.on("uncaughtException") Jan 17, 2024
@leona
Copy link

leona commented Jan 31, 2024

Same issue here. Example:

process.on('uncaughtException', function(err){
  console.log("caught2")   
})

try {
 setTimeout(() => {
  throw new Error("error")
 }, 1000)
 await new Promise((resolve) => setTimeout(resolve, 3000))
 console.log("done")
} catch(e) {
 console.log("caught")
}

Throws error on Bun, prints caught2 on node.

@rivy
Copy link

rivy commented Feb 4, 2024

Multiple event/signal handlers are missing for WinOS.

// t-events-signals.js
// ...works in NodeJS...

// Signal events
[`SIGBREAK`, `SIGINT`, `SIGUSR1`, `SIGUSR2`, `SIGTERM`].forEach((eventType) => {
	process.on(eventType, catchSignal.bind(null, eventType));
});
// IPC events
[`disconnect`, `message`].forEach((eventType) => {
	process.on(eventType, catchEvent.bind(null, eventType));
});
// Process exceptions and promise rejection events
[`uncaughtException`, `unhandledRejection`, `rejectionHandled`, `warning`].forEach((eventType) => {
	process.on(eventType, catchEvent.bind(null, eventType));
});
// Process exit events
[`beforeExit`, `exit`].forEach((eventType) => {
	process.on(eventType, catchExit.bind(null, eventType));
});
// Process worker event
[`worker`].forEach((eventType) => {
	process.on(eventType, (exitCode) => catchEvent.bind(null, eventType)(exitCode));
});

function catchSignal(eventType) {
	// upon a SIGINT, parent/shell may display a '^C'
	// * use an initial '\r' to reset line position, allowing overwrite of any initial '^C'
	console.log('\r' + 'Caught signal...', { eventType });
}
function catchEvent(eventType) {
	console.log('Caught event...', { eventType });
}
function catchExit(eventType, exitCode) {
	console.log('Now exiting...', { eventType }, { exitCode });
}

// emit unhandledRejection
const _foo = new Promise((_resolve, reject) => {
	setTimeout(() => {
		reject('foo');
	}, 300);
});

// emit uncaughtException
setTimeout(() => {
	throw ('bar');
}, 500);

setTimeout(() => {
	console.log('The service is now finished.');
}, 2000);

Note that NodeJS catches all SIGBREAKS and SIGINTS and the uncaught/unhandled errors, ending with an exit code of 0.

> node "t-events-signals.js"
Caught event... { eventType: 'unhandledRejection' }
Caught event... { eventType: 'uncaughtException' }
Caught signal... { eventType: 'SIGINT' }
Caught signal... { eventType: 'SIGINT' }
Caught signal... { eventType: 'SIGBREAK' }
Caught signal... { eventType: 'SIGBREAK' }
Caught signal... { eventType: 'SIGBREAK' }
Caught signal... { eventType: 'SIGBREAK' }
Caught signal... { eventType: 'SIGINT' }
The service is now finished.
Now exiting... { eventType: 'beforeExit' } { exitCode: 0 }
Now exiting... { eventType: 'exit' } { exitCode: 0 }

bun exits with errors and only catches the beforeExit and exit events and ends with a 1 error exit code.

> bun run "t-events-signals.js"
error: foo
Now exiting... {
  eventType: "beforeExit",
} {
  exitCode: 0,
}
Now exiting... {
  eventType: "exit",
} {
  exitCode: 1,
}
``

@pvlvld
Copy link

pvlvld commented Feb 19, 2024

bun --watch just logs all throws, I wonder if it is possible to implement a similar interception of throws by a listener.
Such a badly needed feature.

@SiebeBaree
Copy link

+1, I need this feature for my discord bot shard to not restart on every uncaught thrown exception

@11xdeveloper
Copy link

+1 for the reason above

@supfiger
Copy link

+1 because alongside with this issue #9629 these features are very needed.

@dunadain
Copy link

+1 for I'm going to write a game server based on bun. I need to log uncaught exceptions

@Exitium-DEV
Copy link

+1

@Jarred-Sumner
Copy link
Collaborator

we'll add this a little after bun v1.1

@Jarred-Sumner
Copy link
Collaborator

This will be shipped in Bun v1.1.8, which releases in a couple hours from this comment.

To get it now:

bun upgrade --canary

@rivy
Copy link

rivy commented May 9, 2024

Thanks for the improvements!
Most of the signals are now being caught.
For WinOS, 'SIGBREAK' is still being missed and causing process exceptions/panics.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
atw enhancement New feature or request node.js Compatibility with Node.js APIs
Projects
None yet
Development

Successfully merging a pull request may close this issue.