Skip to content

Deploy a release

A release comes in three forms, from https://github.com/ziyangliu-666/FastMM/releases and PyPI, all with the same version (Versions and compatibility).

Form What it holds Use it for
fastmm-<version>-x86_64.tar.gz fastmm-live, fastmm-gateway, fastmm-ctl, fastmm-top, fastmm-pnl, fastmm-replay, fastmm-sim-exchange, fastmm-sim-itch, the simulator configs, the systemd units, the Prometheus alert rules (0.2.0: fastmm-live, fastmm-top, fastmm-replay, fastmm-sim-itch and fastmm-live.service) a host that runs C++ strategies
ghcr.io/ziyangliu-666/fastmm:<version> the same programs without the simulator, non-root a container host
pip install "fastmm-engine[live]" the engine as a Python package, for strategies written in Python Python

Both are built for x86-64-v2. The tarball needs glibc 2.28 or newer and nothing else (Ubuntu 20.04, Debian 10, RHEL 8, Amazon Linux 2023 and later): OpenSSL, libstdc++ and libgcc are linked in. Each release's tarball is run on Ubuntu 22.04 and 24.04, Debian 12, Rocky Linux 9 and Amazon Linux 2023 before it is published. Neither holds a strategy of your own: a C++ strategy is linked into your own fastmm-live build (Register a strategy).

Install the tarball

URL=https://github.com/ziyangliu-666/FastMM/releases/download/v0.2.0
curl -LO $URL/fastmm-0.2.0-x86_64.tar.gz
curl -LO $URL/fastmm-0.2.0-x86_64.tar.gz.sha256
sha256sum -c fastmm-0.2.0-x86_64.tar.gz.sha256
sudo tar xzf fastmm-0.2.0-x86_64.tar.gz -C /opt
sudo ln -sfn /opt/fastmm-0.2.0-x86_64 /opt/fastmm
/opt/fastmm/bin/fastmm-live --version

An upgrade is a second directory and a new symlink target. Stop the session before you move the link: fastmm-top refuses a status file written by another build. To keep the pause to one restart, run the new build with --takeover from its own directory (Hand over a running session); the old unit exits 0 on the handoff and systemd does not restart it.

scripts/package-release.sh builds the tarball from a checkout. Its default preset, release-dpdk, links in the DPDK receive backend (Receive a multicast feed); --preset picks another. A tarball built on the host needs that host's glibc or newer; --container builds in manylinux_2_28 with docker, as the release does, and scripts/check-release.sh <tarball> runs it on the five distributions.

Run under systemd

deploy/fastmm-live.service is in the tarball and the repository. One unit per engine: one config, one journal directory, one status file.

sudo useradd --system --home-dir /var/lib/fastmm --shell /usr/sbin/nologin fastmm
sudo install -d -o fastmm -g fastmm /var/lib/fastmm /var/lib/fastmm/runs
sudo install -d -m 0750 -o root -g fastmm /etc/fastmm
sudo install -m 0640 -o root -g fastmm my-live.toml /etc/fastmm/live.toml
sudo install -m 0644 /opt/fastmm/deploy/fastmm-live.service /etc/systemd/system/
sudo systemctl daemon-reload && sudo systemctl start fastmm-live

/etc/fastmm/fastmm-live.env holds FASTMM_CONFIG and the API keys the config reads as ${VAR}, root-owned, mode 0600. An unset variable exits 2 before anything connects (Keys).

FASTMM_CONFIG=/etc/fastmm/live.toml
FASTMM_API_KEY=...
FASTMM_API_SECRET=...

What the unit sets:

Directive Why
Restart=on-failure, RestartPreventExitStatus=2 3 5 6 7 8 a crash (any signal, kill -9 included) or exit 4 restarts after 2 s: the new session restores the position from the store and the venue's executions and cancels the orders the dead one left (Run in production). 2 and 3 need a config fix, 5, 6 and 7 a human (Errors and exit codes), and 8 means another process holds the instance lock; a latched kill switch exits 6 at every start. StartLimitBurst=5 in ten minutes ends a crash loop
TimeoutStopSec=90 SIGTERM pulls the quotes and cancels every order over REST before the process exits (Kill switch and shutdown)
LimitMEMLOCK=infinity [engine] lock_memory = true calls mlockall(), which fails with a warning without it. Drop the line when lock_memory is off
#LimitRTPRIO=50, #AmbientCapabilities=CAP_SYS_NICE commented out. [engine] rt_priority and net_rt_priority set SCHED_FIFO, which needs either line (LimitRTPRIO at least the highest priority configured); without them the session warns and runs on the default scheduler. Uncomment one only with the threads on isolated cores (Real-time scheduling)
CPUAffinity=2 3 the cores the process may use, a superset of [engine] cpu and net_cpus and disjoint from everything else on the host. Pair it with isolcpus, nohz_full and rcu_nocbs (scripts/host-setup.sh tune), and delete the line on a shared host, where cpu = -1 (Go-live checklist)
MemorySwapMax=0, OOMScoreAdjust=-500 a swapped-out or OOM-killed engine leaves orders resting at the venue with nothing to cancel them
ReadWritePaths=/var/lib/fastmm ProtectSystem=strict makes the rest of the filesystem read-only; journals, the epoch file and the kill file live here

[engine] cpu_dma_latency_us needs write access to /dev/cpu_dma_latency, which the unit does not grant: add the udev rule in Host tuning.

Logs: stderr carries the lines at [logging] mirror_level and above, so journalctl -u fastmm-live -f shows the warnings and errors, and [logging] file takes the full log for a rotation you own. Journal files grow without a cap (The journal).

systemctl status fastmm-live                 # the exit code of the last run
journalctl -u fastmm-live -f
/opt/fastmm/bin/fastmm-top --name <engine name>
sudo rm /var/lib/fastmm/runs/<engine name>.kill   # clears a latched max_loss trip

Run the container

The image runs as uid 10001 with no login shell, trusts the distro CA bundle, and runs tini as PID 1 to forward signals and reap children. It holds no simulator, no test certificates and no configuration: the first argument is a config path.

mkdir -p runs && sudo chown 10001:10001 runs
docker run --rm --name fastmm \
  -v "$PWD/live.toml:/etc/fastmm/live.toml:ro" \
  -v "$PWD/runs:/var/lib/fastmm/runs" \
  -e FASTMM_API_KEY -e FASTMM_API_SECRET \
  --stop-timeout 90 \
  ghcr.io/ziyangliu-666/fastmm:0.2.0 /etc/fastmm/live.toml --duration 60s
Path in the container Mount
/etc/fastmm/live.toml the config, read-only. CMD uses this path when you pass no argument
/var/lib/fastmm/runs journals, the epoch file and the latched kill file; the host directory has to be writable by uid 10001
/dev/shm/fastmm-<name>.status the status file. docker exec fastmm fastmm-top reads it from inside the container

--stop-timeout 90 gives the cancel-all the same room as the systemd unit. Do not restart a container that exited with 2, 3, 5, 6 or 7. Docker's restart policies cannot exclude exit codes, so use --restart no, or an orchestrator that restarts only on a signal or exit 4, as the unit does.

Other programs run through the same entrypoint by name: docker run --rm -v "$PWD/runs:/var/lib/fastmm/runs" ghcr.io/ziyangliu-666/fastmm:0.2.0 fastmm-replay --journal /var/lib/fastmm/runs/<file>.fmj --verify.

Build it from a checkout with docker build -f deploy/docker/Dockerfile.production -t fastmm:local .. deploy/docker/Dockerfile and deploy/docker/compose.yml are the demo instead: they run as root with test certificates and a simulated exchange (Install).

Next: Run in production, then the Go-live checklist.