真实技术栈
Processes
danwo stops everything it starts, when a run passes, fails, is interrupted or is killed. Here's how, and what your app should do.
A run starts browsers, workers, your apps and their children. When it ends, nothing it started is left running, whether it passed, failed, was interrupted with Ctrl-C or was killed outright.
What danwo cleans up
| Started by danwo | Stopped when |
|---|---|
| your apps and everything they spawn | the worker ends |
| test workers | the run ends, or their parent goes away |
| browsers and their contexts | each test ends |
| emulators and the proxy | the worker ends |
How an app is stopped
Each app's command runs as the leader of its own process group. A dev command often starts the real server as its child, and stopping the group stops both:
- the group gets
SIGTERM; - five seconds later, anything still running gets
SIGKILL.
The same happens on Ctrl-C, SIGTERM or SIGHUP. If the worker itself is killed, a small guardian
process notices and ends what the worker owned.
Windows has no process groups, so there danwo ends the app's whole process tree with
taskkill /T /F. That stop is immediate: Windows has no SIGTERM that a console program obeys,
so the app gets no five seconds to close. The guardian works on Windows too, as long as the
command danwo started (often cmd.exe running your dev command) still runs: Windows finds a tree
through each process's parent, and a process whose parent has exited is no longer part of it.
Have your app exit on SIGTERM: close its server and database pool, then exit. It will stop in
well under five seconds.
Start your own processes the same way
An environment that starts a process itself, such as a search server or a mock service, should use
spawnOwned. It takes the same arguments as Node's spawn and gives the child a stop():
import { spawnOwned } from "@danwo/sdk"
export async function startSearch(): Promise<() => Promise<void>> {
const search = spawnOwned(
"typesense-server",
["--data-dir", "/tmp/search", "--api-key", "test"],
{
stdio: "inherit",
},
)
return async () => {
await search.stop()
}
}The child gets the same treatment as your apps: its own group, SIGTERM then SIGKILL, and the
guardian if the worker dies.