Package version
@adonisjs/core@6.18.0 @adonisjs/ace@13.3.0
Describe the bug
node ace does not exit in Docker when the app is bind-mounted from Windows/WSL
I isolated this to a minimal reproduction repo with a Dockerfile and exact commands:
https://github.com/jakeb-k/node-ace-self-exit
The reproduction includes:
- a clean Adonis starter app
- the Docker config used to reproduce it
- exact commands and observed exit codes
- a toggleable local workaround showing the difference between normal behavior and a forced exit after command completion
Summary
When running node ace inside a Linux Docker container against an app bind-mounted from a Windows/WSL working tree, some non-staysAlive commands do not terminate on their own after the command work is done.
In the repro:
node ace list can take much longer than expected to exit
node ace test stays alive until killed by timeout
- the same app exits normally when
/app/node_modules comes from a Docker-managed volume instead of the bind-mounted working tree
This is a blocker for autonomous agent workflows such as Claude/Codex, because they wait for the process to exit before proceeding.
Expected behavior
Non-staysAlive Ace commands should terminate once the command has completed and Adonis has finished shutdown.
Actual behavior
In the repro environment, node ace test does not terminate on its own.
Example from the repro:
docker run --rm \
-e APP_KEY=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \
-e HOST=0.0.0.0 \
-e LOG_LEVEL=info \
-e PORT=3333 \
-v 'C:\Users\jk_we\Desktop\apps\node-ace-self-exit:/app' \
-w /app \
node:22-bookworm-slim \
timeout 60s node ace test
Observed result:
[ info ] booting application to run tests...
NO TESTS EXECUTED
Observed exit code:
Reproduction repo
Repo:
https://github.com/jakeb-k/node-ace-self-exit
Files of interest:
REPRO.md
Dockerfile
docker-compose.yml
bin/console.ts
REPRO.md contains the full environment details, exact commands, and the active-handle dump.
What I narrowed down
The repro suggests this is related to the loader path used by the starter:
import 'ts-node-maintained/register/esm'
await import('./bin/console.js')
In the repro, importing ts-node-maintained/register/esm inside the bind-mounted environment is enough to produce the problematic behavior pattern.
I also captured active handles and saw a ref'd MessagePort in the failing case that is absent when /app/node_modules comes from a Docker volume.
I am not claiming the root cause is necessarily inside Ace/Core itself. The point of the issue is:
- there is a reproducible environment where
node ace ... does not terminate reliably for non-staysAlive commands
- this is user-visible and blocks tooling/automation workflows
- the repro is isolated enough to inspect with a Dockerfile and exact commands
Workaround included in the repro
The repro app also includes a local opt-in workaround in bin/console.ts:
--force-exit
--no-force-exit
ADONIS_ACE_FORCE_EXIT=true
With that toggle enabled, the same node ace test command exits 0 instead of timing out.
I am not opening this as “Ace should always call process.exit()”. I am opening it because there is a reproducible non-exit scenario, and the workaround demonstrates that an opt-in forced exit after normal shutdown resolves the operational problem for CI/agent tooling.
If this issue is confirmed, I can follow up with a PR against adonisjs/core for an opt-in force-exit path after normal command shutdown.
Reproduction repo
https://github.com/jakeb-k/node-ace-self-exit
Package version
@adonisjs/core@6.18.0 @adonisjs/ace@13.3.0
Describe the bug
node acedoes not exit in Docker when the app is bind-mounted from Windows/WSLI isolated this to a minimal reproduction repo with a
Dockerfileand exact commands:https://github.com/jakeb-k/node-ace-self-exitThe reproduction includes:
Summary
When running
node aceinside a Linux Docker container against an app bind-mounted from a Windows/WSL working tree, some non-staysAlivecommands do not terminate on their own after the command work is done.In the repro:
node ace listcan take much longer than expected to exitnode ace teststays alive until killed bytimeout/app/node_modulescomes from a Docker-managed volume instead of the bind-mounted working treeThis is a blocker for autonomous agent workflows such as Claude/Codex, because they wait for the process to exit before proceeding.
Expected behavior
Non-
staysAliveAce commands should terminate once the command has completed and Adonis has finished shutdown.Actual behavior
In the repro environment,
node ace testdoes not terminate on its own.Example from the repro:
Observed result:
Observed exit code:
Reproduction repo
Repo:
https://github.com/jakeb-k/node-ace-self-exitFiles of interest:
REPRO.mdDockerfiledocker-compose.ymlbin/console.tsREPRO.mdcontains the full environment details, exact commands, and the active-handle dump.What I narrowed down
The repro suggests this is related to the loader path used by the starter:
In the repro, importing
ts-node-maintained/register/esminside the bind-mounted environment is enough to produce the problematic behavior pattern.I also captured active handles and saw a ref'd
MessagePortin the failing case that is absent when/app/node_modulescomes from a Docker volume.I am not claiming the root cause is necessarily inside Ace/Core itself. The point of the issue is:
node ace ...does not terminate reliably for non-staysAlivecommandsWorkaround included in the repro
The repro app also includes a local opt-in workaround in
bin/console.ts:--force-exit--no-force-exitADONIS_ACE_FORCE_EXIT=trueWith that toggle enabled, the same
node ace testcommand exits0instead of timing out.I am not opening this as “Ace should always call
process.exit()”. I am opening it because there is a reproducible non-exit scenario, and the workaround demonstrates that an opt-in forced exit after normal shutdown resolves the operational problem for CI/agent tooling.If this issue is confirmed, I can follow up with a PR against
adonisjs/corefor an opt-inforce-exitpath after normal command shutdown.Reproduction repo
https://github.com/jakeb-k/node-ace-self-exit