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

node: process.on("beforeExit") #2331

Merged
merged 6 commits into from
Jul 19, 2022

Conversation

bartlomieju
Copy link
Member

@bartlomieju bartlomieju commented Jun 9, 2022

Blocked by denoland/deno#14830

@bartlomieju bartlomieju requested a review from kt3k as a code owner June 9, 2022 18:03
node/process.ts Outdated Show resolved Hide resolved
process.js Outdated Show resolved Hide resolved
@CLAassistant
Copy link

CLAassistant commented Jun 28, 2022

CLA assistant check
All committers have signed the CLA.

Comment on lines +410 to +413
"test-process-beforeexit.js",
"test-process-binding-internalbinding-allowlist.js",
"test-process-env-allowed-flags.js",
"test-process-exit-from-before-exit.js",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great!

@andreubotella
Copy link
Contributor

I have looked a bit into this, and from what I can tell, in Node next ticks aren't enough to keep the event loop alive. If there are any ticks enqueued in the beforeExit event listener, they will run, but they won't cause another beforeExit event to be fired.

We could fix this by removing the presence of next ticks from the conditions that keep an event loop alive, but then the various places in the CLI that fire a beforeunload event must make sure to also run the next ticks callback before firing the unload event.

@bartlomieju
Copy link
Member Author

@andreubotella i think that's preferable behavior. We did remove next tick checks but then had trouble with second to last callback. I think your solution is gonna alleviate that. @cjihrig what do you think?

@cjihrig
Copy link
Contributor

cjihrig commented Jul 11, 2022

That sounds like a worthwhile plan to me.

@andreubotella
Copy link
Contributor

andreubotella commented Jul 11, 2022

It looks like my description of the issue above was essentially correct, but the fix I proposed wasn't. Next ticks by themselves can't keep the event loop alive, but async ops in their callbacks can. Therefore, it's not enough to drain the next ticks queue once after firing the beforeunload event – the queue has to be drained before determining whether to continue running.

I opened nodejs/node#43787 to test this behavior.

Since the event loop's pending status determines whether the beforeunload is canceled, for beforeExit, I think the next ticks queue should be drained from the beforeunload event listener before checking the pending status. This would mean there's no need to drain the queue for regular beforeunload events (as I suggested above), but I think we still should do that, for consistency between beforeunload and beforeExit.

@@ -258,6 +262,13 @@ class Process extends EventEmitter {
constructor() {
super();

globalThis.addEventListener("beforeunload", (e) => {
super.emit("beforeExit", process.exitCode || 0);
if (core.eventLoopHasMoreWork()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This event listener should call into processTicksAndRejections from next_tick.ts before checking if there's more work. That would be enough to fix this issue, with no need to change Deno's event loop.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean like this:

    globalThis.addEventListener("beforeunload", (e) => {
      super.emit("beforeExit", process.exitCode || 0);
      processTicksAndRejections();
      if (core.eventLoopHasMoreWork()) {
        e.preventDefault();
      }
    });

If so, that doesn't seem to get deno test -A --unstable node/_tools/test.ts -- parallel/test-process-beforeexit.js passing.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't pass with Deno 1.23.4, but for me it's working with canary.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, right - because denoland/deno#14830 hasn't been released yet 🤦 . It's working for me with latest main.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for figuring it out @andreubotella!

@bartlomieju bartlomieju changed the title [WIP] node: process.on("beforeExit") node: process.on("beforeExit") Jul 18, 2022
@bartlomieju bartlomieju requested a review from cjihrig July 18, 2022 23:27
@bartlomieju bartlomieju merged commit 25a80ab into denoland:main Jul 19, 2022
@bartlomieju bartlomieju deleted the process_on_beforeexit branch July 19, 2022 00:57
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

Successfully merging this pull request may close these issues.

5 participants