Issues / #3407

#3407 [Engine] serve/lifeline.py: the portable watcher does not end the child when the child's ps state changes (test_lifeline fails 5/5 on Linux)

open · @Norhiro · 0 comentários · No GitHub

Setup & installServer & APIWindowsLinux

Descrição

### Area

[Engine]  (speed, kernels, models, the server and API)

### Desktop app, Terminal or source?

Source (START-HERE.bat, setup.sh or a build)

### What happened

Expected: with `STRATA_LIFELINE=watcher`, killing the server ends its child. Actual: the child keeps running.
`serve.test_lifeline.Lifeline.test_the_portable_watcher_ends_the_child_when_the_server_is_killed` fails on every run on this machine (5 of 5 runs alone, and in the full Python suite):

```
AssertionError: False is not true : the child outlived a killed server (watcher)
```

The other five tests in the module pass, including `test_a_child_ends_when_its_server_is_killed` (the Linux `pdeathsig` path). So this concerns the portable watcher, which Linux uses only when `STRATA_LIFELINE=watcher` is set. As far as I can tell from the code, macOS uses it by default.

From reading `serve/lifeline.py`: the start token is `"s:" + ps -o lstart=,stat= -p PID`, so it includes the process **state**. `_start_token()` runs right after the child starts, while the child is still running (`R`). When the watcher's pipe closes, `start_of()` sees the child sleeping (`S`). The tokens differ, the watcher assumes the PID was reused, and it does not signal the child. The state change is easy to show:

```
>>> c = subprocess.Popen([sys.executable, "-c", "import time; time.sleep(5)"])
>>> ps -o lstart=,stat= -p c.pid        -> '火 10月 20 16:11:52 2026 R'
>>> (1 s later)                          -> '火 10月 20 16:11:52 2026 S'
```

**Suggested change (tested here)**

Use only the start time for the token and keep the state just to detect a zombie. In both `_WATCHER.start_of()` and `_start_token()`:

```python
    if not out or out.endswith("Z"):
        return None                       # "" in _start_token
    return "s:" + out.rsplit(None, 1)[0]  # lstart only: the state (R/S/D, +, l ...) changes during a process's life
```

With this change in a copy of the tree, `serve.test_lifeline` passed 6/6 tests on 5 of 5 runs. `lstart` is in the locale's format (Japanese here). It is still compared with itself, so the locale should not matter.

### Smallest steps or command that reproduce it

```
python -m unittest serve.test_lifeline
```

### Reproduction status

Reproduced locally

### Strata version

Strata 0.2.0-beta · engine 0.1.45.3 (source, commit `3d1fb480`). `main` on 2026-10-20 still has `ps -o lstart=,stat=` at lines 103 and 138.

### Graphics card, memory and system

Not GPU related. 2 × Xeon E5-2630 v2 (Ivy Bridge-EP, AVX without AVX2/FMA), 252 GB DDR3, Fedora 44 (kernel 7.2.5), Python 3.14.7, procps-ng 4.0.6.

No site

Links install, modelos, releases.