Machines and from()
Run each job on its own Sandbox, and start a job from another job's machine to reuse its work.
Inngest CI is an Inngest Labs project: early, moving fast, and shaped by your feedback. What's Labs?
A machine is a Sandbox: an ephemeral Linux microVM. Each job gets one on its first command, and only commands run on it. The rest of your handler runs in your app.
vcpu | Memory |
|---|---|
| 1 | 1 GiB |
| 2 (default) | 2 GiB |
| 4 | 4 GiB |
Set machine on a job, on its pipeline, or on createCi for every job. The first one set wins in that order.
- Commands run in
/workby default, which is wherecheckout()puts the repository. checkout()clones the commit that triggered the run with a short-lived token that never appears in the trace. Locally it uploads your working tree without its.gitfolder.- Inngest pauses a machine when its job passes and destroys every machine when the pipeline ends.
Start a job from another job
from(job) starts the current job on a copy of another job's machine, like a Docker layer. Use it when several jobs need the same setup, such as installed dependencies, so the setup runs once.
const base = ci.job("base", async () => {
await checkout();
await $`pnpm install`;
});
const build = ci.job("build", async () => {
await from(base);
await $`pnpm build`;
});
const test = ci.job("test", async () => {
await from(build);
await $`pnpm test`;
});
The parent runs once, however many jobs start from it, and each child gets its own isolated copy. If the pipeline already called the parent directly, from() uses that run. from() shares a job's machine within one run. To reuse it across runs, give the parent a cache key. Each job builds on the snapshot of the one before it.
What happens under the hood
When a job finishes, Inngest pauses its machine. When another job calls from(), Inngest snapshots the parent's machine and starts the child from a clone of that snapshot, so installed files and built output are already there. The snapshot and clone come from Sandbox snapshots and restore.
If a snapshot is not available, the job runs the parent's commands again on its own machine. The result is the same, but every child repeats the parent's work.
from()resolves once the copy is ready. Pass the parent's input as the second argument when it takes one.- Call
from()before the job's first command, and once per job. await base()runsbaseon its own machine.await from(base)runs it and then starts this job from where it finished.- Choose the parent at runtime with
await from((await changed("docs/**")) ? docsBase : base).
When a parent has a cache key, an unchanged key skips the parent and restores its saved machine instead.
Use a second machine
sandbox(name, { vcpu }) creates another machine for the job right away, with the job's machine settings unless you pass others. It is destroyed with the pipeline and appears under the job in the trace.
const verify = ci.job("verify", async () => {
await checkout();
const clean = await sandbox("clean", { vcpu: 1 });
await Promise.all([
$`pnpm test`,
clean.$.sh`npm install -g my-cli@next && my-cli --version`,
]);
});
This runs the tests on the job's machine while a clean machine checks that the published next build installs.
Plain $ still runs on the job's own machine, and an extra machine starts empty.
Machines cannot reach each other yet. Run a server or database your tests call on the job's own machine, in the background, and use 127.0.0.1:
await $`pnpm start`.background();
await waitForPort(3000);
await $`pnpm exec playwright test`;
| If the work... | Use |
|---|---|
| Is independent | Separate jobs |
| Builds on earlier work | Separate jobs with from() |
| Needs a second machine alive at the same time | One job with sandbox() |