Ship batesd as a Mix release; fix bates start crash#32
Open
tylerhunt wants to merge 8 commits into
Open
Conversation
PR #31 added a `bates start` subcommand to the existing escript, but it crashed immediately because escripts cannot carry `erlexec`'s `priv/exec-port` C binary. The escript packaging format is the wrong tool for the daemon. This removes `Bates.CLI.Start`, the dispatcher clause that routed `start` to it, the `bates start` line in the usage banner, and the test file. The matching usage assertion in `Bates.CLITest` is updated. A subsequent commit will reintroduce the daemon as a Mix release named `batesd` so `erlexec`'s priv directory is available at runtime.
The control commands previously told users to run `bates start` when the daemon was unreachable. With `bates start` removed and the daemon shipping as a Mix release named `batesd`, the diagnostic now reads "Bates is not running. Start it with: batesd." Also rewords `Bates.Prerequisites` and `Bates.CLI.Setup` docstrings to describe the gates and setup work in terms of `batesd`.
Move the argv parser, config-path application, and prereq verifier that the doomed `Bates.CLI.Start` owned into `Bates.Application.start/2` so the same supervision tree boots correctly under both `mix phx.server` and `bin/batesd` (the upcoming Mix release). The work lives in a new `Bates.Daemon` module as three pure helpers (`parse_argv/1`, `apply_options/1`, `verify_prerequisites/0`) so each piece is unit-testable without trapping `System.halt/1`. `start/2` itself is a thin orchestrator that halts with code 2 on parse or prereq failures, matching what `bates start` used to do. Tests run `Application.start/2` because `:bates` is a started application. To keep them from tripping the prereq gate (or being rejected by the argv parser, which sees `["test"]`), `config/test.exs` sets `config :bates, skip_prereq_check: true`, and `start/2` short- circuits the entire boot prep when that flag is set. The default of `false` keeps the gate active in dev and in the release. `Bates.Daemon` does NOT call `Mix.env/0` or any other build-time module: `Mix` is unavailable in releases. New `Bates.DaemonTest` covers `--config` parsing (default + override), unknown-switch and unexpected-positional rejection, application of the parsed `--config` to `:bates, :config_path`, and the prereq diagnostic when `caddy` is off `$PATH`.
Declare a `batesd` Mix release in `source/mix.exs`'s `releases:` keyword. The release embeds ERTS, includes every dependency's `priv/` directory, and starts `:bates` permanently — so `erlexec` finds its `exec-port` C binary at runtime, which the escript packaging format could not deliver. `mix release` generates `bin/batesd` as a multi-subcommand dispatcher (`start`, `daemon`, `remote`, `eval`, ...). A custom `:steps` callback (`install_launcher/1`) renames that file to `bin/batesd-orig` and writes a thin wrapper at `bin/batesd` that always invokes the foreground `start` subcommand. Users see a single command: `batesd [--config <path>]` — no subcommand maze. The wrapper is written directly inside the `:steps` callback rather than via `rel/overlays/`. Overlays are copied during `:assemble`, which makes the rename-then-overlay sequence awkward; doing the rename and the wrapper write in the same custom step keeps the ordering obvious. Add a minimal `config/prod.exs` so `MIX_ENV=prod mix release batesd` can read environment-specific endpoint settings. The file mirrors `dev.exs` for now (port and `secret_key_base`); follow-up work can diverge as needed. `config/runtime.exs` is intentionally absent — the release reads its only environment-dependent setting (`--config <path>`) from argv inside `Bates.Application.start/2`.
`specs/cli.md` removes the `### bates start` section and the option table that came with it, points the not-running message at `batesd`, points the configuration override description at `batesd`, and rewords the "How It Connects" `bates start` bullet to describe `batesd`. A new `## Daemon` section documents `batesd`'s flags, prereq behavior, and intended invocation (foreground until the launchd v2 proposal lands). The intro paragraph now describes the two binaries explicitly. `specs/system-overview.md`'s `### CLI` section now spells out the two-binary topology: `batesd` is the server (Mix release, embeds ERTS so `erlexec` finds its priv binary), and `bates` is a thin client escript for the control commands.
Add a "Build and Run" section between "Setup" and "Configuration" covering both binaries: `mix escript.build` for the `bates` client and `MIX_ENV=prod mix release batesd` for the daemon. Includes the `--config` flag, the foreground/Ctrl-C semantics, and a couple of sample `bates` invocations against a running daemon.
The mix-release `start` subcommand discards extra argv, and the generated `elixir` launcher's CLI mode interprets argv as `[script | args]` (so passing `--config` directly would make it treat the flag as a script filename). Have the `bin/batesd` wrapper parse `--config` in shell and export it as the `BATES_CONFIG_PATH` environment variable, then add `Bates.Daemon.apply_env/1` to plumb that into `:bates, :config_path`. `Bates.Application.start/2` now runs the env step after argv so the env var wins when both are set (the wrapper sets it deliberately; the argv path stays for `mix phx.server`).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Context
PR #31 added a
bates startsubcommand to the existing escript, but itcrashes immediately because escripts cannot carry
erlexec'spriv/exec-portC binary. The escript packaging format is the wrong toolfor the daemon. This PR splits Bates into two binaries:
batesstays asan escript for the six fast-cold-start control commands, and the daemon
ships as a Mix release named
batesd.Summary
bates startsubcommand and its module + tests.--config <path>) and prerequisite verificationinto
Bates.Application.start/2(viaBates.Daemon), so thesupervision tree boots the same way under
mix phx.server(dev/test)and
bin/batesd(release).releases:keyword tomix.exsdeclaring thebatesdreleasewith a custom
:stepscallback that installs a thinbin/batesdwrapper. The wrapper parses
--configin shell, exportsBATES_CONFIG_PATH, and execs the underlying mix-release launcher'sstartsubcommand. The daemon picks upBATES_CONFIG_PATHviaBates.Daemon.apply_env/1. (See execution notes in the archived planfor why the env-var path was needed instead of plain argv forwarding.)
config :bates, skip_prereq_check: trueinconfig/test.exssomix testdoesn't trip the prereq gate on dev machines withoutcaddyon$PATH.config/prod.exsso the prod release assembles.batesd, notbates start.specs/cli.mdandspecs/system-overview.mdfor the newtwo-binary topology.
Test plan
The agent has run automated checks. The sections below need to be
verified by hand before merge — they require live Caddy / DNS resolver
and real services to bring up.
mix testfromsource/passes (235 tests, 0 failures).mix format --check-formattedpasses.MIX_ENV=prod mix release batesdsucceeds and produces_build/prod/rel/batesd/bin/batesd._build/prod/rel/batesd/bin/batesd --helpdoes NOT print themix-release subcommand list (the wrapper took).
_build/prod/rel/batesd/bin/batesd --bogusexits 2 with ourusage message.
BATES_CONFIG_PATH=/tmp/x.toml batesd-orig eval ...confirms thedaemon reads the env var into
:bates, :config_path._build/prod/rel/batesd/bin/batesdboots and serves the dashboardat
https://bates.test.bates status,bates up <app>,bates env <app>all workagainst the running daemon.
bin/batesd --config /path/to/foo.tomlhonors the override.batesdwhile one is already up exits with aport-bind error.