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

v11.11.0 timeout.refresh() does not seem to prevent event loop from exiting #26642

Closed
ahwayakchih opened this issue Mar 13, 2019 · 3 comments
Closed
Labels
confirmed-bug Issues with confirmed bugs. timers Issues and PRs related to the timers subsystem / setImmediate, setInterval, setTimeout.

Comments

@ahwayakchih
Copy link

ahwayakchih commented Mar 13, 2019

  • Version: v11.11.0
  • Platform: Alpine Linux v3.9 run inside Docker on Linux 03891e4323dc 5.0.0-arch1-1-ARCH #1 SMP PREEMPT Mon Mar 4 14:11:43 UTC 2019 x86_64 Linux
  • Subsystem: Timers

When using timeout.refresh to keep re-running some code, Node.js v11.x exits process, even though timeout is supposed to be "ref'ed" by default (and it is: timeout.hasRef() returns true every time).

I am not 100% sure, but i think it might be caused by this line:

if (refed === !item[kRefed]) {

Shouldn't it look like this instead?

if (refed !== item[kRefed]) {

Problem is 100% reproducible with following example (save it to file and run, e.g., node test-timer.js or DEBUG=1 node test-timer.js):

process.on('exit', () => console.log('Bye!'));

const DEBUG = Number(process.env.DEBUG) || false;
var countdown = 2;
var timer = setTimeout(run, 0);

function run () {
	console.log('run', countdown--);
	if (countdown < 1) {
		console.log('all done');
		clearTimeout(timer);
		return;
	}
	timer.refresh();
	// Uncomment next line to make this work on Node.js v11.x
	// timer = setTimeout(run, 0);
	if (DEBUG) {
		console.debug('has ref?', timer.hasRef ? timer.hasRef() : timer);
	}
}

When run on v11.11.0, actual output is incorrect:

run 2
Bye!

When run on v10.15.3, actual output is correct:

run 2
run 1
all done
Bye!

Changing amount of time, e.g., from 0 to 1000, does not change the output.
Number assigned to countdown does not matter either, as long as it's greater than 1 ;).

@ahwayakchih
Copy link
Author

ahwayakchih commented Mar 13, 2019

My guess about possible buggy line was wrong. I changed it but it did not help. Sorry.

But that line is part of the problem. When commented out, refCount is correctly updated and process does not exit. With that line, refCount is incremented only once, when insert is called for the first time.
But refCount is decremented every time timeout function is called:

node/lib/timers.js

Lines 345 to 346 in 32853c0

if (timer[kRefed])
refCount--;

Shouldn't call to timeout.refresh() somehow increment refCount? At least, if timeout function was called before. If it was not called yet, refCount was not decremented, so it should not be incremented.

At the moment, very ugly and hacky workaround is to use timer._repeat = true instead of calling timer.refresh(), and timer._repeat = false when it's time to stop it :(. Nevermind: that would keep repeating the function even when it shouldn't.

@starkwang starkwang added the confirmed-bug Issues with confirmed bugs. label Mar 14, 2019
@starkwang
Copy link
Contributor

Reproduced in 11.11.0 and the master.

@starkwang starkwang added the timers Issues and PRs related to the timers subsystem / setImmediate, setInterval, setTimeout. label Mar 14, 2019
@starkwang
Copy link
Contributor

cc @nodejs/timers

starkwang added a commit to starkwang/node that referenced this issue Mar 15, 2019
If a timer is refreshed in its callback, we should not decrease `refCount`
to prevent exiting event loop ahead of time.

Fixes: nodejs#26642
@danbev danbev closed this as completed in 4306300 Mar 20, 2019
targos pushed a commit that referenced this issue Mar 27, 2019
When `timers.refresh()` is called inside a callback, the timer would
incorrectly end up unrefed and thus not keep the event loop alive.

PR-URL: #26721
Fixes: #26642
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Richard Lau <riclau@uk.ibm.com>
Reviewed-By: Weijia Wang <starkwang@126.com>
Reviewed-By: Anto Aravinth <anto.aravinth.cse@gmail.com>
Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
confirmed-bug Issues with confirmed bugs. timers Issues and PRs related to the timers subsystem / setImmediate, setInterval, setTimeout.
Projects
None yet
2 participants