# Supervising Ordinary Processes: A Docker-Free Service Cluster Manager in Rust

Daozhendong Yang, School of Intelligent Science and Engineering,
Yunnan Technology and Business University, Kunming, China — <hi@yxpil.com>

Paper about **maylin**, a service cluster manager that runs services as ordinary
host subprocesses (no container runtime, no images), with plugin templates,
restart policies, cron scheduling, token-based roles, a load balancer, and a
WebSocket attach endpoint.

## arXiv classification

- **Primary:** `cs.DC` — Distributed, Parallel, and Cluster Computing
- **Cross-lists:** `cs.OS` — Operating Systems; `cs.SE` — Software Engineering

The same classification is stated in the header comment of `main.tex`.

## Abstract (plain-text rendering of the LaTeX abstract; identical wording)

Maylin is a small service cluster manager, written in Rust, that supervises
ordinary host processes instead of containers. A service is a command line
assembled from a plugin template—a runtime executable, a script, and three
placeholders—so Node, Python, and native programs share one lifecycle: six
observable states, restart policies, health probes, an event log, and an
HTTP/WebSocket control plane with token-based roles. This paper describes that
supervision model and measures it against a real build on Windows. With
max_retries = 3, a crashing child is launched four times, with measured gaps of
2.05, 4.07, and 6.05 s, and is then marked failed; a child that exits 0 is
launched once and left exited. Stopping a child that ignores stdin takes 1.21 s
with a 1 s grace period. Restarting an instance with four requests in flight
loses all four when it is the only upstream, but loses none with two, at the
cost of 2 duplicate side effects in 6 executions. An authorization matrix over
18 method–path pairs and 4 principals shows that every endpoint rejects
anonymous callers, but also that role checks are per-route heuristics rather
than per-object policy, and that several endpoints return 500 or hang instead
of failing cleanly. Maylin provides no isolation, no reproducible images, and
no consensus: it is a deliberate midpoint between systemd, supervisord, and
Compose, and the paper is explicit about what that midpoint gives up.

## File manifest

| Path | Contents |
| --- | --- |
| `main.tex` | Paper source: 11 pages, two columns, four figures, three tables |
| `refs.bib` | Bibliography database (32 entries; only cited entries appear in the PDF) |
| `common.tex` | Shared preamble, copied from `papers/_shared/common.tex` |
| `figures/architecture.pdf` | Figure 1, deployment shape |
| `figures/supervision.pdf` | Figure 2, instance state machine |
| `figures/backoff.pdf` | Figure 3, measured backoff against the `2n` schedule |
| `figures/authz.pdf` | Figure 4, authorization matrix heatmap |
| `figures/*.png` | Raster previews of the same figures, not used by LaTeX |
| `scripts/measure_supervision.py` | Measurement harness (standard library only) |
| `scripts/make_figures.py` | Figure generator (matplotlib) |
| `scripts/results/supervision.json` | Every measured number in the paper |
| `README.md` | This file |

## Build

Requires a TeX distribution with `pdflatex`, `bibtex`, `natbib`, and
`abbrvnat.bst` (TeX Live or MiKTeX).

```sh
cd papers/maylin
pdflatex main
bibtex main
pdflatex main
pdflatex main
```

The result is `main.pdf` (11 pages). The two final passes are needed for
cross-references; `bibtex` emits no warnings after the first pass.

## Package for submission

From the directory that contains `papers/` (the paper-collection root):

```sh
bash papers/make_package.sh maylin
```

This writes `papers/dist/maylin.tar.gz` and injects `common.tex` if the paper
directory does not already contain it.

## Submit

<https://arxiv.org/submit> — choose `cs.DC` as the primary category and add
`cs.OS` and `cs.SE` as cross-lists. Upload the tarball produced above, or
`main.tex`, `refs.bib`, `common.tex`, and `figures/` individually. The paper has
no external dependencies beyond the TeX distribution named above.

## Reproduce the measurements

Prerequisites: a Rust toolchain, Python 3.9+ (the harness imports only the
standard library), and matplotlib for the figures.

```sh
# 1. Build the binary that was measured.
cargo build

# 2. Re-run experiments a-e (about 80 s of wall clock plus daemon startup).
python papers/maylin/scripts/measure_supervision.py \
  --binary target/debug/maylin \
  --out papers/maylin/scripts/results/supervision.json

# 3. Regenerate every figure from the JSON.
python papers/maylin/scripts/make_figures.py \
  --results papers/maylin/scripts/results/supervision.json \
  --outdir papers/maylin/figures
```

On Windows use `target/debug/maylin.exe`. A subset can be re-run with
`--only a,b` (the accepted keys are `a`, `b`, `c`, `d`, `e`). The harness starts
its own daemon on a private port for each experiment, writes fixtures under a
temporary directory, and reads timings back from the daemon's event log
(`data/events.jsonl`) rather than from wall-clock guesses.

Test suites, for reference:

```sh
cargo test
```

On the reference host these gave 28 unit tests passing in 0.04 s, 4
authentication/injection tests passing in 5.42 s, and the 11-step end-to-end
test passing in 17.52 s. The end-to-end test is sensitive to orphans: its
cleanup calls `kill` on the daemon, and on Windows that does not terminate the
children, which keep ports 13301 and 13302 bound and make the next run fail.
Two earlier attempts failed for this reason (at the failover step and at the
direct-connect step); the reported pass followed killing the orphans. This is
reported in §5.7 of the paper.

## What this paper does not claim

- **No isolation.** Services run as the daemon's user with the host's
  filesystem, network, and environment. The security boundary is the operating
  system user, not the service.
- **No reproducible images.** A service is a command line, not an artifact; an
  interpreter upgrade on the host changes the service at its next restart.
- **No consensus, membership, leadership, or reconciliation.** Peers are a
  static list; two nodes may run the same instance name and nothing detects it.
- **No claim that the terminal is a shell.** The WebSocket endpoint writes to a
  running service's stdin and tails its log; `/api/exec` is the arbitrary
  command endpoint, and it is administrator-only.
- **No claim of exponential backoff.** The code computes `2n` seconds capped at
  30; the project's own documentation says otherwise, and §5.2 reports the
  measured sequence.
- **No claim that health checks restart anything.** Three failed probes set the
  instance to `unhealthy`; the supervisor does not act on that state.
- **No performance claims.** The measurements are one host, one platform
  (Windows), four requests per condition, debug build. They establish direction
  and order of magnitude, not throughput or a latency distribution.
- **No claim to replace Kubernetes, systemd, or supervisord.** The paper argues
  only for a narrow midpoint and states what that midpoint gives up.
- **Not a multi-tenant system.** Roles are global (`viewer`, `operator`,
  `admin`); there is no per-instance or per-object grant.

## Data provenance

Every number in `main.tex` is either in `scripts/results/supervision.json`
(experiments a–e, generated by `measure_supervision.py`) or is a static count
taken from the repository at commit `3c285fe` (source lines, modules, routes,
test functions, plugin templates). No number was typed by hand into the
measurement scripts; the paper's text was written from the JSON.
