Repository navigation
Concepts
The rest of this guide uses a small set of terms: workflows and rules, the steps and samples that rules stand for, launches and attempts, budgets and requests, rule keys and records. This page defines each once.
flowchart LR
workflow -- lists --> rule
rule -- is an instance of --> step
rule -- works on --> sample
step -- belongs to --> category
step -- runs --> tool
launch -- makes --> attempt
attempt -- runs --> rule
A workflow is a TOML file that lists rules. Its directory is the working directory, unless a command is given -d DIR. Relative paths in the workflow resolve against the working directory, a rule's command starts there unless the rule sets a workdir, and kanit keeps its records in .workz/ inside it.
kanit reads the graph as written. Samples, parameters and file names are expanded before kanit reads the file: by kanit prepare from a pipeline template, or by a program of your own (Writing workflows).
A rule has a name, a list of input files, a list of output files, one shell command and a request for threads and memory. Rule B depends on rule A when one of B's inputs is one of A's outputs; this is the only way rules are connected. An input that no rule produces is an external input, a file that must exist before the rule runs.
A rule's outputs must be files inside the working directory. Inputs may be anywhere, including a reference directory elsewhere on the machine. A directory can be an input; its identity then covers every file and directory below it, so a change to any of them counts as a change to the input.
A workflow runs a few commands on many pieces of data, one rule for each pair. Four labels on a rule say which pair it is:
- A step is what the rule does in the pipeline, such as
STAR_ALIGNortrim. Rules that run one command on different data are instances of one step, and the step is what reports size and compare: six alignments make one row. - A sample is the data the rule works on, such as
ctrl1. A rule that combines every sample, such as a count matrix or a MultiQC report, has none. - A category groups steps by purpose, such as
qc,alignmentorquantification. - A tool is the program the step runs, such as
STAR; a rule'sversioncommand records which version ran (Writing workflows).
Part of an RNA-seq workflow, labelled:
| Rule | Step | Sample | Category | Tool |
|---|---|---|---|---|
fastp_ctrl1 |
FASTP |
ctrl1 |
trimming | fastp |
star_ctrl1 |
STAR_ALIGN |
ctrl1 |
alignment | STAR |
star_treat1 |
STAR_ALIGN |
treat1 |
alignment | STAR |
sort_ctrl1 |
SAMTOOLS_SORT |
ctrl1 |
alignment | samtools |
counts |
COUNT_MATRIX |
quantification | gawk | |
multiqc |
MULTIQC |
report | MultiQC |
A rule declares its labels with the keys step, sample, category and tool (Workflow reference). A label it does not declare is taken from its name and image:
- The step is the text after the last
__(ctrl1__STAR_ALIGNisSTAR_ALIGN), else the text before the last_(align_ctrl1isalign), else the whole name. - The sample is the text before the last
__(ctrl1). A name without__has none. - The tool is the image's name without its registry and tag (
quay.io/biocontainers/star:2.7.11b--h5ca1c30_8isstar). A host rule takes the program itsversioncommand runs (samtoolsforsamtools --version | head -1), and has none without one. - A rule has a category only when it declares one.
Tip
A generator knows each rule's step and sample, so let it write them (Writing workflows). Names then stay free: without a declared step, count_genes is read as the step count.
Labels are not part of the rule key: adding or changing one reruns nothing. Each attempt records them, and they are used in three places:
- Reports size and compare steps, add up time per category and tool, and find the slow sample of each step.
- The HTML report colors attempts by category and draws a table of samples by steps.
- The scheduler estimates a rule that has never completed by the median wall time of its step (Resources and scheduling).
A launch is one execution of kanit run. Each launch gets an ID made of its UTC start time and a random suffix, such as 20261026T033653.780-bb9b10ee, and a directory in .workz/launches/.
Within a launch, each rule that runs has one or more attempts, numbered from 1. A failed attempt is retried while the rule has retries left. Each attempt keeps its command, request, standard output and error, and a record of what it used, in .workz/launches/<ID>/attempts/<rule>/<NNN>/.
A rule moves through these states in a launch:
stateDiagram-v2
[*] --> pending
pending --> reused: unchanged since its last run
pending --> waiting: its producers completed
pending --> blocked: a producer failed
waiting --> running: the budget has room
running --> completed: exit 0 and every output written
running --> retrying: failed, retries left
retrying --> waiting
running --> failed: failed, no retries left
running --> stopping: stopped, or the launch stops
stopping --> cancelled
waiting --> cancelled: stopped before it started
pending --> not_started: the launch ended first
waiting --> not_started: the launch ended first
A waiting rule is ready to run but does not fit yet; kanit records what it waited for, such as threads, memory or a resource group. A stopping rule has been sent SIGTERM and is given its grace period to end. A launch that stops after a failure leaves the rules it never started not_started; one that is interrupted or cancelled marks them cancelled. Running workflows describes failures, retries and cancellation.
A launch has a budget: a number of threads (--max-threads, default every online CPU), an amount of memory (--max-memory, default three quarters of the machine's memory) and a number of jobs (--jobs, default the thread budget). Each rule's request reserves threads and memory from the budget while it runs, and a rule starts only when its request fits in what is free.
The request is also a limit. With isolation, the default, each attempt runs in its own cgroup: its threads become a CPU quota, and its memory becomes a hard limit. An attempt that needs more memory than it requested is killed as out of memory, all of its processes together. Resources and scheduling explains admission, limits and the order in which ready rules start.
A resource group is a named counter with a capacity, for limits the budget cannot express: at most two rules that read from the same disk, or one rule that holds a licence. A rule takes units of a group while it runs.
A shared input is a large read-only file, such as a genome index, that many rules read. kanit loads it into memory once, before its first user starts, and counts its memory once against the budget, however many rules use it. A shared service is a container that holds such an index in shared memory for container rules that join it (Containers and services).
Each time a rule completes, kanit records its rule key: a digest of everything that decides its result, from its command, keyed environment and request to the identities of its inputs, the keys of the rules that produce them and the engine key (the rule key lists each part). A rule is reused in a later launch when its key is the same and its outputs are still the files it wrote. Anything else makes it run again, and its consumers follow.
A file's identity is its inode, size, and modification and change times, so kanit notices an edited file without reading it. Some files are keyed on their content instead (Reuse and resume).
Everything kanit knows about earlier launches is in .workz/: state.json, with the rules completed since it was written in state.log, holds the key and outputs of every completed rule, and each launch directory holds its event stream, summary and attempts. The commands that show a launch only read these files, so they work from any terminal while the launch runs and after it ends. Records describes every file.
-
Engine: the
kanit runprocess that drives a launch. It starts attempts, watches them and writes the records; the reports give its own CPU time and memory as its cost. - Scope: the transient systemd user unit a launch runs in, which holds its cgroups and limits it to the budget (Isolation).
- Cgroup: a Linux control group. With isolation, each attempt runs in one, which enforces its request and counts what it used.
- Holder: the process that keeps a shared input's files in memory while rules still need them.
- Podman: the rootless container runtime that runs container rules and shared services (Containers and services).
kanit user guide for release 0.9.0. kanit is licensed under Apache-2.0.
Start
Write workflows
Run and observe
Reference