emscripten-core / emscripten-core/emscripten

Defining setStatus with headless flag causes node process to silently exit...

Open
#22,793 7 comments 0 reactions 0 assignees View on GitHub
Dominant language
C++
Stars
27.6k
Forks
3.6k
Avg merge
1d 1h
Merged PRs (30d)
105

Description

**Version of emscripten/emsdk:**

emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.47-git
clang version 16.0.6
Target: wasm32-unknown-emscripten
Thread model: posix
InstalledDir: /nix/store/2sbmywkxfmjw5wbn53vxqckm0xm8yffs-emscripten-llvm-3.1.47/bin

**Issue Description:**

I'm working on a project with a complex make file, so sharing the exact command that's being run will be a bit difficult, as I'm not super familiar with `make`.

That being said, I have a fairly good understanding of what's happening, so let me try to break it down:

- I'm compiling with `-s HEADLESS=1` so that I can run an SDL project in node.js ([doom-wasm](https://github.com/cloudflare/doom-wasm) running as a dedicated server)
- I'm compiling with `-s MODULARIZE=1`, and running `const module = await createModule(...)` to construct the module
- Nothing after the await runs, and the process exists, despite having a sleep loop that should hold the process open
- if I remove `setStatus` from the options object passed to `createModule`, it works as expected

This was quite baffling to me, but eventually I realized that:
- if `setStatus` is defined, `doRun` is run inside of a `setTimeout`
- if `HEADLESS` is defined, `setTimeout` is replaced by a custom implementation
- this custom implementation doesn't actually cause anything to be placed on the node event loop
- thus, if you're awaiting the promise returned by `createModule`, then the event loop runs out of things to do, and the process silently exits.

You can see a minimal reproduce of this if you simulate the `readyPromiseResolve` bit manually:

```js
let resolve, reject;
const p = new Promise((res, rej) => { resolve = res; reject = rej; });

await p;
console.log("after p");
```

Even though there's a dangling promise being "awaited" on, there's not actually anything on the event loop that could cause the `resolve` to... resolve... so the process just exits.

This is *really* surprising, given the lack of documentation for `-s HEADLESS`, and the fact that it's only triggered if a seemingly unrelated methods, `setStatus`, is defined.

(I noticed some conversations like #20554 mention that this isn't well maintained, so it's also worth weighing in on HEADLESS being useful for non-testing use cases, so if there's a recommended alternative to running emscripten projects with an emulated browser environment, would also love that advice!)

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.