真实技术栈

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 danwoStopped when
your apps and everything they spawnthe worker ends
test workersthe run ends, or their parent goes away
browsers and their contextseach test ends
emulators and the proxythe 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:

  1. the group gets SIGTERM;
  2. 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():

search.ts
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.

Next

本页内容

在每个 Pull Request 上运行

每个 Pull Request 一个 GitHub Check 和一条评论,并附上完整的运行记录。

配置 CI