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

Workers only pipe one message to stdout before they stop running #53701

Open
realriccio opened this issue Jul 2, 2024 · 7 comments
Open

Workers only pipe one message to stdout before they stop running #53701

realriccio opened this issue Jul 2, 2024 · 7 comments
Labels
worker Issues and PRs related to Worker support.

Comments

@realriccio
Copy link

realriccio commented Jul 2, 2024

Version

22.4.0 (i also tried earlier versions and the bug is always present)

Platform

Both in Linux and Windows, all OS versions.

Subsystem

worker_threads

What steps will reproduce the bug?

const { Worker } = require("worker_threads");

let worker = new Worker(`function print_three_and_work(){
	console.log("a");
	console.log("b");
	console.log("c");

	while(true){}
}

print_three_and_work();`, {eval: true});

or

const { Worker } = require("worker_threads");

let worker = new Worker(`function print_three_and_work(){
	console.log("a");
	console.log("b");
	console.log("c");

	while(true){}
}

print_three_and_work();`, {eval: true, stdout: true});

worker.stdout.on("data", function(chunk){
	process.stdout.write(chunk);
});

How often does it reproduce? Is there a required condition?

It always happens.

What is the expected behavior? Why is that the expected behavior?

All logged messages should be piped to the main thread's stdout while the worker is running.

What do you see instead?

Only the first message is piped. All other messages are not piped while the worker is running. They get piped all at once once the worker stops running.

(I see "a" instead of seeing "a \n b \n c".)

Additional information

#40961

I believe this other issue has a similar problem but it was misunderstood as having something to do with "process.exit", while instead it must be because of something else.

@RedYetiDev RedYetiDev added the worker Issues and PRs related to Worker support. label Jul 2, 2024
@RedYetiDev
Copy link
Member

@nodejs/workers


Possible duplicate of #40961

@climba03003
Copy link
Contributor

climba03003 commented Jul 3, 2024

Not really the duplicate of #40961
It is known that console is async operation and while (true) block all the async I/O.
So, it never been possible for the write operation to run.

If we turns in something that hold the Worker but allows async I/O. It works as expected.

import { Worker } from 'node:worker_threads';

let worker = new Worker(`function print_three_and_work(){
  console.log("a");
  console.log("b");
  console.log("c");
  
  // hold the thread, but allow async I/O
  setTimeout(() => {}, 1000)
}

print_three_and_work();`, {eval: true, stdout: true});

worker.stdout.on("data", function(chunk){
  process.stdout.write(chunk);
});

Or use sync operation and write to fd.

import { Worker } from 'node:worker_threads';

let worker = new Worker(`
const { writeSync } = require('node:fs')
function print_three_and_work(){
  writeSync(1, "a\\n")
  writeSync(1, "b\\n")
  writeSync(1, "c\\n")

  while(true) {}
}

print_three_and_work();`, {eval: true, stdout: true});

worker.stdout.on("data", function(chunk){
  process.stdout.write(chunk);
});
@realriccio
Copy link
Author

Why is there such a difference between the behaviour of console.log inside of workers and on the main thread? If i run the same function normally instead of giving it to a worker, it works at expected (if it didn't this weird behaviour would have been noticed by many before me):

Code:

function print_three_and_work(){
	console.log("a");
	console.log("b");
	console.log("c");

	while(true){}
}

print_three_and_work();

Output:

a
b
c
@climba03003
Copy link
Contributor

climba03003 commented Jul 3, 2024

As stated inside the linked issue.
console inside Worker is always async I/O, but main thread is not guarantee to be sync or async.
image

So, if the result is printed right away, that means it is sync right now.

@realriccio
Copy link
Author

Oh ok, i didn't know that, thanks. Is there a way to force the console to flush all messages before continuing with sync work?

@climba03003
Copy link
Contributor

climba03003 commented Jul 3, 2024

You should use fs.writeSync if you need consistent result.
You can write to the fd: 1 for stdout.

@mcollina
Copy link
Member

mcollina commented Jul 3, 2024

I recommend using console.log() only for debugging and not in any production scenario.

Use pino for logging. Internally, it uses sonic-boom. Both can be set up to log synchronously, like so:

const pino = require('pino')
const logger = pino(pino.destination({
  dest: 1, // stdout
  sync: true // Synchronous logging
}))

logger.info({ foo: 'bar' }, 'my message from %s', 'Italy')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
worker Issues and PRs related to Worker support.
4 participants