- The Linux build runs as always. When the server has an online Windows runner, it passes
-Patoll.runners=windowsto Gradle, and the platform’s init script turns the configured Windows formats (TargetFormat.Msi,TargetFormat.Exe) into work for a runner instead of a note. - After the Linux build, the server queues one job per OS, and on macOS a separate one for the iOS app,
so a failing iOS build does not drop the
.dmg/.pkg. A runner claims a job, builds the same source with the same build env vars, and uploads the files. They join the target’s files on the deployment. On shared runners each job’s minutes count separately. - If no runner picks the job up within 15 minutes, the job runs longer than 60 minutes, fails, or the org is on the free plan without a runner of its own, the target is still deployed with what Linux built and a note says what is missing.
Shared runners and your own
An org’s jobs go to its own runners first:
- A job of an org with an own runner of that OS online waits for one of them. Shared runners leave it alone for
ATOLL_RUNNERS_SHARED_FALLBACK_SECONDS(2 minutes), then the first free runner takes it. - Without an own runner online (or all of them draining) shared runners take the job at once.
- When billing refuses shared runners (free plan, spend limit) but the org has an own runner of that OS online, the job is queued for its own runners only, and the log says so. Without one the target gets a note instead.
- Minutes of jobs an org’s own runner ran are not recorded.
The two parts of atoll-runner
The agent starts each build through an executor:
Because of that, a runner reports whether its builds are isolated, and the server limits what a non-isolated one
gets:
- A non-isolated runner (
--executor direct) must be registered with a token pinned to one org and only ever gets that org’s jobs. A stolen runner token then reaches no other org’s source or env vars. - A runner not pinned to an org serves every org and must be isolated. If its agent ever polls without isolation, it gets no jobs.
direct still does to contain a build: the build gets a minimal environment (PATH, JAVA_HOME, temp and
profile directories, the job token; nothing of the agent’s own settings or its token file path), runs in a fresh
directory under atoll-runner-jobs that only the agent’s user can open, and everything it started is killed when it
ends (a Windows job object; on macOS and Linux its process group). The agent takes no new job while processes of the
previous build are still alive. If you can, run the agent as a dedicated OS user whose home holds nothing else;
running builds as yet another user is not supported yet.
Until the VM executors exist, the agent refuses to start unless you pass --executor direct.
Requirements
- A JDK 17 or newer on
PATHor inJAVA_HOME(the project’s Gradle wrapper picks its own Gradle). - Windows: Windows 10 or Server 2019 or newer (for
tar.exe). Compose downloads WiX 3 itself for.msiand.exe. - macOS: Apple silicon with Xcode and its command line tools, for
.dmg,.pkgand unsigned iOS simulator apps (see iOS apps). iOS apps need an up-to-dateatoll-runner: older macOS runners keep building installers but don’t take iOS jobs, and the deployment notes that the runner needs an update. - Outbound HTTPS to the server’s public URL. Runners need no inbound ports.
Register a runner
Everything starts with a one-time registration token, valid for 24 hours by default. Your org’s runner. In the panel open Runners and click Add runner (org admins): it shows the token and the commands for macOS and Windows. Or with the API:--executor direct.
A shared runner. A platform admin (a verified email in ATOLL_AUTH_ADMIN_EMAILS, or the ATOLL_TOKEN holder on a
server without accounts) creates the token. For a direct runner, dedicate it to the org (by slug) whose deployments
it builds:
"org" the token only registers isolated runners, shared by every org. On a server without accounts the
panel’s Runners page creates tokens for org local, which every project is in; runners are kept in memory there,
so register them again after a restart.
On the runner host, as the account the agent will run as:
%ProgramData%\atoll-runner\runner.json on Windows or
~/.config/atoll-runner/runner.json elsewhere (change it with --token-file), readable by that account only. The
registration token is used up.
Labels are key=value pairs. os is required (windows or macos); jobs need os=<their OS> and go to the
oldest waiting job’s first free matching runner. --labels defaults to the host’s os and arch.
Run the agent
As a Windows service
Use a dedicated local user for the service, register as that user, and point the service at its token file. With NSSM:As a launchd daemon (macOS)
/Library/LaunchDaemons/app.atoll.runner.plist:
sudo launchctl bootstrap system /Library/LaunchDaemons/app.atoll.runner.plist. (Until the Tart executor
exists, add --executor direct and read the warning above.)
Rotate and revoke
compromised and stops its build; register the host
again with a new registration token.
Rotate from the panel (or POST .../rotate) when the host is out of reach or the token may have leaked: the
runner’s token stops working at once, a build it runs goes back to the queue, and you get a one-time registration
token. Running atoll-runner register with it on the host (the panel shows the command, with the runner’s name and
labels) gives the same runner a new token; it keeps its id, org and history. Only the newest rotation token works.
Restart the agent afterwards; a service restarts it by itself.
Drain a runner before maintenance: it finishes its job and takes no new ones until you resume it.
Remove a runner to take it out for good; its running job goes back to the queue. Removed runners can’t come back,
register the host again instead.
Server settings
Runners call the public
/api/runners/... paths with bearer tokens, never with a session, so the server’s public URL
is all they need. Tokens are stored as SHA-256 hashes.
Protocol
For people writing executors. All calls sendX-Atoll-Runner-Protocol: 1.
The executor starts
atoll-runner build --server <url> --job <id> with the job token in ATOLL_JOB_TOKEN, in an
empty directory. A VM executor would copy the atoll-runner binary into a fresh VM, run that command there, stream
its output back to the agent and destroy the VM afterwards.