Docs

Budgets

Measure a tool's WebAssembly execution, add headroom, and check the host's ceilings before publishing or deploying its budget.

budget on [tools.<tool>] in crab.toml bounds one invocation. The build embeds it in the image; changing it requires rebuilding and redeploying.

Units, defaults and ceilings

Key Unit in crab.toml Default when omitted Default host ceiling
cpu Microseconds 100_000 (100 ms) 100_000 (100 ms)
read Rows read 1_000_000 1_000_000
written Rows written 10_000 1_000_000
memory MiB 128 128

CPU measures execution time rather than time waiting for HTTP; SQL CPU is reported separately.

Every explicit value must be at least 1. Omission uses the default; it does not mean zero or unlimited. In particular, cpu = 500_000 means 500 ms, above the default 100 ms ceiling.

Hosts can configure different defaults and ceilings. The local host's --max-cpu-millis changes its CPU ceiling; raising it does not change Cloud's. A budget above the destination's ceiling is refused at deployment with E0013, even when the image built successfully.

Size a budget before deployment

crab bench builds and measures an explicit workload in a temporary host, estimates its cost, and checks a budget suggestion against runtime defaults. Use it before requesting deployment.

  1. Define the largest inputs and data sets the tool supports: request and response sizes, batch counts, parser complexity and database size. Enforce those bounds in the tool.
  2. Start with a provisional budget within the destination's ceilings. Use crab bench <directory> <tool> --cases cases.jsonl --runs 10 with representative and worst-case inputs, including error paths, or exercise them on the local host. Native Rust tests and image builds do not measure WebAssembly execution; host tests run the actual image and can arrange HTTP responses.
  3. Read the tool's own usage in the benchmark report, or the usage printed on stderr by crab call. CPU is in microseconds. Benchmark memory is in bytes; crab call prints KiB. Divide by 1_048_576 or 1024, respectively, to get MiB. Use peak linear memory, not memory held in MiB-seconds, when choosing memory. A run stopped by its budget has not measured the resources needed to finish.
  4. Add headroom to each measured maximum: a starting point is ceil(1.5 × maximum), with a minimum of 1. Convert memory to MiB before rounding up. Compare every resulting key with the destination's ceiling. Headroom that exceeds a ceiling does not fit: 80 ms × 1.5 is 120 ms, above a 100 ms CPU ceiling.
  5. Put the values in crab.toml, rebuild, redeploy locally and repeat the workload under those budgets before requesting a Cloud deployment or publishing a template. CPU time can vary across machines; recheck Cloud usage after deployment.

For example, from a service directory:

crab --context default deploy
crab --context default call app search '{"query":"example"}'

Illustrative measurements of 8,000 µs CPU, 200 rows read, 2 written and 12 MiB peak memory give:

[tools.search]
access = "public"
budget = { cpu = 12_000, read = 300, written = 3, memory = 18 }

If the supported workload cannot finish with headroom below the ceiling, reduce its resource use or supported input bounds and measure again. Split work across calls when the operation supports batching or pagination. Lowering a declaration alone does not make the work fit.

Measurements after deployment

crab budget <service> <tool> prints usage over the last 30 days and a fits suggestion with 1.5× headroom. CPU and row estimates use runs that ended done: each measure's maximum below 100 runs, and its 99th percentile from 100 runs. Failed runs are excluded from those estimates. Memory uses the largest recorded linear memory of the tool's own invocations.

The suggestion does not check host ceilings, and observed traffic does not establish the worst case for every supported input. Check it against both the ceilings and your workload before using it.

Budgets apply to an invocation's own CPU, rows and memory; calls to other services use their own budgets. crab call, the Ran.meter from host tests, and the CPU and row estimates used by crab budget include nested calls. These chain totals are conservative bounds for the entry tool's own use; a chain above one tool's ceiling does not establish that tool exceeds it. Exercise called tools separately too.

crab inspect <service> shows each public tool's budget. Billing and memory held: Cost of a call.

Past a budget

  • CPU. The call is stopped, within 100 ms of crossing it.
  • Rows. Once a call has read its rows read or written its rows written, its next statement that reads or writes is refused, and the service can handle the error. The statement that crossed the budget runs to its end.
  • Memory. The growth that would pass it fails, and with it the call.

A call reserves its memory budget during execution, waiting on fetches or other services included, and is billed for that reservation. Loading cold service code is excluded. berm_lang::limit can lower it for one call; its memory argument is in bytes, unlike crab.toml's MiB.