Service management
Seamless services (hashserver, database, jobserver, daskserver) are launched and
supervised by remote-http-launcher, a separate package that manages process
lifecycle, SSH tunnels, and state files. This guide covers how to inspect, stop,
restart, and clear services during normal development and debugging.
Two-layer design
Service management is split across two layers:
-
rhl-*helpers (fromremote-http-launcher): operate on raw keys — opaque identifiers thatremote-http-launcheruses for its JSON state files. They run on whichever machine holds the state (server-side forrhl-stop,rhl-logs, etc.; client or server forrhl-rm). They have no knowledge of Seamless clusters, projects, or stages. -
seamless-service-*wrappers (fromseamless-config): accept Seamless-level arguments (--service,--cluster,--project,--stage) and translate them torhl-*calls. They run client-side and dispatch to the right host over SSH.
As a Seamless user, you typically use only the seamless-service-* layer. The
rhl-* helpers are available for lower-level access when you already know the
key (e.g., from seamless-service-resolve).
Viewing service state: seamless-service-ps
# List client-side connection state (fast, no SSH):
seamless-service-ps
# List server-side process state for a cluster:
seamless-service-ps --server --cluster MYCLUSTER
# Include persistent data state (buffer dirs, seamless.db):
seamless-service-ps --server --persistent --cluster MYCLUSTER
# Filter by project or status:
seamless-service-ps --server --project myproject --status stale
Example output with --persistent:
SERVICE PROJECT STAGE PROCESS PORT PERSISTENT SIZE
hashserver myproject - running 10501 populated 42 MB
hashserver myproject fingertip stale - populated 17 MB
database myproject - running 10502 populated 3 MB
jobserver myproject fingertip failed - n/a -
Process states: running | starting | failed | stale | absent
Persistent states: populated | empty | absent | n/a (non-persistent
services such as jobserver and daskserver use /tmp and have no durable data)
Stopping and restarting services
# Stop a specific service (reads defaults from seamless.yaml + seamless.profile.yaml):
seamless-service-stop --service hashserver
# Stop with explicit args:
seamless-service-stop --service hashserver --cluster MYCLUSTER --project myproject
# Stop all services for a cluster:
seamless-service-stop --cluster MYCLUSTER
seamless-service-stop sends SIGINT → SIGTERM → SIGKILL with short polling
intervals between escalations. It does not remove state JSON files — the
stale state is preserved so you can inspect logs afterwards.
To remove JSON state after stopping:
seamless-service-rm --service hashserver
seamless-service-rm --cluster MYCLUSTER # cluster-wide
To restart: stop, remove, then re-run your script or seamless.config.init().
remote-http-launcher will start the service fresh.
Reading logs
# Stream full log (from project directory — reads seamless.yaml for defaults):
seamless-service-logs --service hashserver
# Last 50 lines only:
seamless-service-logs --service hashserver --tail 50
Note: for non-persistent services (jobserver, daskserver, pure-daskserver), read
the log before removing state with seamless-service-rm. The log file
survives JSON removal but becomes unreachable through the helper once the JSON
is gone.
Inspecting service state JSON
seamless-service-inspect --service hashserver
Prints the full server-side state JSON: PID, port, status, workdir, command,
and the meta block containing service/cluster/project/stage identifiers.
Clearing cached data
Seamless caches transformation results in two places:
- Buffer directory (hashserver): stores actual data bytes, indexed by checksum
- Database (database): stores transformation → result checksum mappings in
seamless.db
Both must be cleared for a true cold-cache re-execution:
# From the project directory:
seamless-service-clear --service hashserver
seamless-service-clear --service database
# With explicit args:
seamless-service-clear --service hashserver --cluster MYCLUSTER --project myproject --stage fingertip
seamless-service-clear --service database --cluster MYCLUSTER --project myproject --stage fingertip
seamless-service-clear errors cleanly for non-persistent services (jobserver,
daskserver, pure-daskserver), which use /tmp and have no data directory to
clear.
Debugging false-pass test results
A test can pass even when the underlying code is broken, because Seamless returns a cached result from a prior successful run. This is the most common source of incorrect "fixes" — the test passes, the developer commits, and the problem resurfaces later.
Signs of a false pass:
- Test passes immediately after a service restart
- Test passes after changes that should have affected results
- seamless-service-ps --persistent shows populated after all processes stopped
Protocol for ruling out a false pass:
# 1. Check what persistent data is present:
seamless-service-ps --server --persistent --project myproject --cluster MYCLUSTER
# 2. Stop and clean services:
seamless-service-stop --cluster MYCLUSTER
seamless-service-rm --cluster MYCLUSTER
# 3. Clear cached data:
seamless-service-clear --service hashserver --project myproject
seamless-service-clear --service database --project myproject
# 4. Restart services and re-run the test on a cold cache.
Only a pass on a cold cache is meaningful.
Service lifecycle reference
| State | Meaning | What to do |
|---|---|---|
absent |
No JSON or data exists | — |
starting |
Process launched, waiting for port | Wait; if it hangs, read log |
running |
Service healthy, port known | — |
failed |
Startup failed or timed out | Read log, fix, restart |
stale |
JSON exists but process is dead | Read log, then seamless-service-rm |
persistent |
Data directory populated, no process | Inspect with --persistent; clear if needed |
For the full rhl-* helper reference and the JSON state file schema, see the
remote-http-launcher README.
Server-side install requirements
seamless-service-* always shells out to the rhl-* helpers — the
wrappers do not carry an inline fallback. remote-http-launcher must
be installed on every remote server that seamless-service-* targets; it
provides all rhl-* helpers. Two supported server-side install paths:
- System install (root required):
pip install remote-http-launcherinto the system Python. Helpers land in/usr/local/bin. - Conda base env install (no root):
pip install remote-http-launcherinto the remote host's conda base environment. Helpers land in$HOME/miniforge3/binor$HOME/miniconda3/bin.
No .bashrc edit is required for either path. seamless-service-*
automatically prepends $HOME/miniforge3/bin:$HOME/miniconda3/bin to
PATH on every SSH call, so conda-base installs work without any shell
startup changes.
remote-http-launcher's own conda-discovery fallback (inline heredoc
probes) covers only the launcher's bootstrap. It does not extend to
seamless-service-*, agents calling rhl-* over SSH, or any other
tooling that depends on the helpers.