# A native deployable

A deployable is one program your app is built into. An app that declares
no `deployables:` has exactly one, `app`: a native server binary that
serves every API and runs all the background work. An app that declares
them is built as [Declared deployables](declared-deployables.md) says.

```text
$ jadpo build
  binary    build/target/app/app
  build     b_e20fc10f5474
  commit    8d113e6
  settings  DATABASE_URL

✓ built  app · native in 49.1 s
→ jadpo migrate apply  it starts only once its database has every migration
```

`jadpo build` and `jadpo build app` build it. Any other name is
`cli.build_arguments`.

## What `jadpo build` writes

It checks as `jadpo check` does, writing the same files in `build/`. At
the first error it stops with the same screen, ending `✗ build stopped`.

Otherwise it writes the deployable's Rust into `build/rust/app/`: the
program's crate, `jadpo-program-app`, and a binary named after the
deployable, with the toolchain this Jadpo pins in `rust-toolchain.toml`
and the runtime crates' `Cargo.lock`. It compiles that in release,
offline and `--locked`, in the release profile its workspace's
`Cargo.toml` gives: fat link-time optimisation in one codegen unit at
`opt-level = 3`, its symbols kept. The paths it was built from are
remapped and `SOURCE_DATE_EPOCH` is fixed: the variable's value when it is
set, else the commit's time.

The binary is `build/target/app/app`, and each API's OpenAPI document and
`<api>.failures.<locale>.json` are copied into `build/target/app/openapi/`.
It is built without the runtime's `testing` feature.

cargo failing is `toolchain.build_failed`, since the Rust Jadpo writes
always compiles. A file it can't write is `toolchain.artifact_write_failed`.

## What it compiles with

Everything a build needs comes with `jadpo` or is fetched by it, so a
released `jadpo` builds anywhere and you don't install Rust. A native
build still needs your machine's C compiler, which links the binary and
compiles `ring`'s cryptography.

- **The runtime crates' source** is carried in the `jadpo` binary, with
  their `Cargo.lock` and the toolchain file.
- **The Rust toolchain** that file pins (`rustc`, `cargo` and the
  standard library for your machine, and wasm32's once a Worker is built)
  is fetched from Rust's download server the first time a build needs it,
  into `jadpo/toolchains/<version>-<host>/` of your cache folder. Each
  archive is checked against the SHA-256 the release's manifest gives, and
  the manifest against the digest this Jadpo pins.
  `JADPO_RUST_DIST_SERVER` names a mirror, whose manifest is checked
  against the `.sha256` beside it.
- **The crates the lock names** come from crates.io, or whatever cargo's
  own configuration puts in its place. cargo fetches them only when its
  cache can't build offline, into `CARGO_HOME` when that is set, else the
  cache folder's `jadpo/cargo/`, each checked against the lock's
  checksum.

Each fetch says what it is fetching (`Fetching Rust 1.99.0 for
aarch64-apple-darwin`, `Fetching the runtime's crates`). Where stderr
animates, it is on the live line, each archive with a bar; otherwise it is
a line on stderr; under `--json` it says nothing. The screen's `fetched`
line, and `--json`'s `fetched`, say what came (`Rust 1.99.0 (146.9 MB)
and 292 crates`). A fetch that fails is `toolchain.fetch_failed`.

With `CARGO` naming a cargo, that cargo builds instead and nothing is
fetched. cargo sets `CARGO` for what it runs, and the gate does for this
repository's tests.

## The build stamp

Every build carries a stamp saying what it is ([Records and
manifest](18-records-and-manifest.md)):

- the build id: `b_` and the first twelve hex digits of a SHA-256 over the
  deployable's program (what it is compiled from: its Rust and its plan,
  its name and its stores' migrations), the compiler's version, the target
  and `jadpo.lock`;
- the commit `git` says the project is at, and whether its tree holds
  changes the commit doesn't (`build/` and `.jadpo/` aside); a project git
  doesn't track has no commit and counts as changed;
- the compiler, the deployable and the target.

The binary holds the stamp as a constant. The runtime plan it holds
records the build id where `jadpo dev` records the graph's digest
([Several changing calls in one
action](11-integrations.md#several-changing-calls-in-one-action)).

## Starting

The binary reads only the variables its settings name, and refuses to
start when one is missing or invalid. It names each setting and its
variable, never the value ([Configuration and
time](10-configuration-and-time.md)).

It builds each connection's driver. One it can't build is listed as it
starts, and answered `misconfigured` when used. A database whose
connection names no `url:` stops the start, since only `jadpo dev` and
`jadpo test` give one an address of their own.

Each database the project keeps migrations in is compared with the
migrations the build holds. A migration not applied, or one applied that
the build doesn't have or that changed since, stops the start
([Migrations](migrations.md)). A database it can't reach yet is
waited for, trying again after 1 second and doubling to 10, since a
database that is down isn't a configuration error.

Then it listens on `PORT` (8080 when unset) on `HOST` (every IPv4
interface when unset), with a worker per core.

## Running and stopping

Each worker serves requests and runs the tick, the runtime's regular
pass over background work. The first SIGTERM or ctrl-c stops it: it
accepts nothing more, answers the requests it is reading, lets its
background work give back what it holds, and ends with code 0. A second
ends it at once. A start that fails ends with code 1.

## Running one tick

The binary takes one command. None, or `serve`, serves as above.
`<deployable> tick` runs one tick and ends ([The
tick](12-jobs-and-events.md#the-tick)). Another scheduler runs it when
`schedules: { trigger: ScheduleTrigger.external }` says the server's own
timer never ticks.

`tick` reads its settings, builds its drivers and compares its stores'
migrations as serving does, but waits for no database: one it can't reach
ends it with code 1, `store_unreachable`. It ends with code 0, or with 1
when the tick couldn't work in a store or didn't finish, having panicked
or outlasted the drain. The first SIGTERM or ctrl-c drains it, giving back
what it holds. Any other command ends with code 2, `command_unknown`,
without repeating what was given.

`jadpo build` gives such a deployable a `tick` line, with the command and
how often to run it (`build/target/app/app tick · each minute`), and
`--json` a `tick` (`command`, `every_ms`).

## What it logs

It logs one JSON object a line on standard output, its keys sorted, each
with the stamp's fields (`build`, `commit`, `modified`, `compiler`,
`deployable`, `target`):

- `runtime.startup_failed`, with every problem that stopped the start
  (`problems`, each with a `problem` code, the setting, variable or store
  it is about, and a `message`);
- `runtime.waiting`, while a database can't be reached;
- `runtime.started`, with the address, workers, `trigger` (`native` or
  `external`) and each connection whose driver wasn't built (`unbuilt`);
- `runtime.ticked`, after each tick, the server's own timer's as well as a
  `tick` command's: `ran`, each schedule it ran or skipped by name with
  its outcome, `deliveries`, `received`, `polled`, `deleted`, `alerts`,
  `problems`, each store it couldn't work in, `unbuilt` and `ms`;
- `operation.failed`, for a fault behind a 500, with its classification,
  route, `request_id` and `.jadpo` frames ([Failures](failures.md),
  [Debugging and review](debugging-and-review.md)). When the fault is a
  bug in Jadpo, `bug_in_jadpo` is `true` and `report` holds the issue
  form's address; otherwise they are `false` and `null`;
- `runtime.stopped`.

The rest of a deployable's log comes with telemetry ([Built-in
services](16-built-in-services.md)).
