# Run a long command

URL: https://briq.cloud/docs/guides/run-a-long-command

> Start a build, a test suite or a data load that takes minutes or hours, check it, read its output and stop it.

`briq_exec` waits for a command for up to a minute. Anything longer (a build, a test suite, a data
load, a migration) runs with `async: true`: briq starts it, answers at once with an exec id, and
you check it until it ends. First, [connect your agent](https://briq.cloud/docs/getting-started).

```text
briq_exec({ briq: "bq_…", cmd: ["sh", "-c", "cd /app && npm ci && npm test"], async: true })
→ ex_7kq2m9x1p4ab running since 10:02 UTC; stopped at 11:02 UTC if still running

briq_exec_result({ briq: "bq_…", exec: "ex_7kq2m9x1p4ab" })
→ ex_7kq2m9x1p4ab exited 0 after 3m
  stdout: …
```

1. The command runs in the briq, in the background, under `sh`.
2. `briq_exec_result` waits up to 30 seconds for it to end, then answers either way. Call it again
   while it runs.
3. Its answer has the state, the exit code once it ends, and the last 64 KB of stdout and stderr.

## Read all of the output

The whole output stays in the briq, in `/tmp/.briq/exec/<exec id>/out` and `err`:

```text
briq_files_get({ briq: "bq_…", path: "/tmp/.briq/exec/ex_7kq2m9x1p4ab/out" })
```

Over 1 MB, read part of it with `briq_exec`: `["tail", "-n", "200", "/tmp/.briq/exec/ex_…/out"]`.

## Stop it

```text
briq_exec_stop({ briq: "bq_…", exec: "ex_7kq2m9x1p4ab" })
→ ex_7kq2m9x1p4ab stopped on request
```

It stops the command and every process it started.

## Set a deadline

`timeoutMs` stops the command when it runs out: one hour by default, 24 hours at most.

```text
briq_exec({ briq: "bq_…", cmd: ["make", "release"], async: true, timeoutMs: 14400000 })
```

## Over REST

```bash
EXEC=$(curl -sf "https://api.briq.cloud/v1/briqs/$ID/exec" -H "Authorization: Bearer $BRIQ_API_KEY" \
  -H "Content-Type: application/json" -d '{ "cmd": ["make", "test"], "async": true }' | jq -r .exec.id)
until STATE=$(curl -sf "https://api.briq.cloud/v1/briqs/$ID/execs/$EXEC?waitMs=45000" \
  -H "Authorization: Bearer $BRIQ_API_KEY") && [ "$(jq -r .exec.state <<<"$STATE")" != running ]; do sleep 5; done
jq -r .exec.output.stdout <<<"$STATE"
```

| Method   | Path                                  |                                                      |
| -------- | ------------------------------------- | ---------------------------------------------------- |
| `POST`   | `/v1/briqs/:id/exec`                  | With `async: true`: 202 `{ exec }`                   |
| `GET`    | `/v1/briqs/:id/execs/:execId?waitMs=` | `{ exec }`; `waitMs` waits up to 45000 for it to end |
| `GET`    | `/v1/briqs/:id/execs`                 | The briq's execs, newest first                       |
| `DELETE` | `/v1/briqs/:id/execs/:execId`         | Stops it                                             |

## States

| State       | Meaning                                                     |
| ----------- | ----------------------------------------------------------- |
| `running`   | Still going                                                 |
| `exited`    | Ended by itself; `exitCode` says how                        |
| `timed_out` | Stopped at its deadline                                     |
| `stopped`   | Stopped by `briq_exec_stop`                                 |
| `lost`      | The machine restarted without it, or the briq was destroyed |

## When it does not work

* **`an async exec needs sh in the image`** (or `setsid`): the image has neither (distroless,
  `scratch`). Run the command without `async` (up to a minute), or use an image that has them.
* **`10 commands are already running`**: a briq runs ten at most. Wait for one, or stop one.
* **`warning: timeoutMs is at most 60000 without async`**: the command ran for a minute at most.
  Run it again with `async: true`.
* **`lost`**: the machine started again from scratch and the command did not survive (a crash,
  or a stop and start of a briq too large to resume from memory). Start the command again.
* **`the briq is stopped, so the command cannot be reached`**: `briq_start` the briq, then stop
  the command. A check on a stopped briq answers with the last state seen.

## Good to know

* **A running command keeps its stack awake**, and billed, until it ends or reaches its deadline,
  whatever the `sleep` setting or a key's `maxSleep`. See [Sleep](https://briq.cloud/docs/concepts/lifecycle-and-sleep).
* **Lost an exec id?** `briq_status` lists the briq's running commands.
* **Checking is use too**, like any call on the stack.
* **Input**: `stdin` works as with `briq_exec`.
* **The output files stay** in the briq until it is destroyed.
