Repository F# setup
open System
open System.IO
open System.Threading
open System.Threading.Tasks
open Axial
open Axial.Console
open Axial.FileSystem
open Axial.PlatformService
open Axial.ProcessWhen a process cannot complete as requested, Process.toFlow fails with
ProcessError. This is the Flow's normal typed error value, not an exception thrown by the child program. Run the
Flow and match Exit.Failure(Cause.Fail error) when this boundary needs to decide what to report or return.
The failure cases
ProcessError case |
When it occurs | Details available |
|---|---|---|
StartFailed |
The executable cannot be started: it is missing, not executable, or the operating system rejects startup. A pipeline can also fail this way after earlier stages have started. | ProcessStartFailure.Command and Message |
TimedOut |
The specification's configured timeout elapses before every stage completes. | Redacted specification and timeout duration |
StageFailed |
A started command exits with a code outside its configured success-code set. This is the usual result for a command that reports failure with a nonzero exit code. | Failed StageResult and the complete ProcessResult |
IoFailed |
Axial cannot read, write, or route one of the process streams or configured file targets. | I/O error message |
For every timeout, cancellation, and partial pipeline startup, Axial terminates stages that did start before the Flow finishes. The typed error tells the caller what happened after cleanup, rather than leaving a child process running in the background.
Cancellation is not a ProcessError. When the caller cancels the enclosing Flow or ends stream consumption early, the
processes are terminated and the Flow ends with Cause.Interrupt. The caller that requested the cancellation decides
what it means by matching the Exit.
Match the error when the caller needs a policy
Show page setup
// Setup for the checked examples on this page.
open System
open System.IO
open System.Threading
open System.Threading.Tasks
open Axial
open Axial.Console
open Axial.FileSystem
open Axial.PlatformService
open Axial.Process
/// Fails the docs test when an example's result differs from the value shown.
let shouldEqual expected actual =
if actual <> expected then failwithf "Expected %A but got %A" expected actual// The examples on this page start real processes with the live service.
let host : ProcessHostEnvironment =
{ Process = Process.live Clock.live FileSystem.live Console.live
Console = Console.live }
host: ProcessHostEnvironmentAxial.Process.ProcessHostEnvironmentThe live environment used by <c>Process.run</c> at a command-line host boundary. Application workflows normally use their own environment record and <c>Process.runWith</c>.
Process: IProcessAxial.Process.ProcessModulelive: IClock -> IFileSystem -> IConsole -> IProcessCreates a live process service using an explicit clock for transcript timestamps and durations.
Axial.PlatformService.ClockHelpers for the clock service.
live: IClockCreates a live clock backed by and a monotonic timer.
Axial.FileSystem.FileSystemModulelive: IFileSystemCreates a live file-system service backed by , , and .
Axial.Console.ConsoleModulelive: IConsoleCreates a live console service backed by .
Console: IConsolelet explain (exit: Exit<ProcessResult, ProcessError>) =
match exit with
| Exit.Failure(Cause.Fail(ProcessError.StartFailed failure)) ->
$"could not start {failure.Command}"
| Exit.Failure(Cause.Fail(ProcessError.TimedOut failure)) ->
$"{failure.Specification} exceeded {failure.Timeout}"
| Exit.Failure(Cause.Fail(ProcessError.StageFailed failure)) ->
$"stage {failure.Stage.Stage} exited {failure.Stage.ExitCode}"
| _ -> "ok"
explain: Exit<ProcessResult,ProcessError> -> stringexit: Exit<ProcessResult,ProcessError>Axial.Exit`2Represents the final outcome of a workflow execution. The type of the success value. The type of the domain-specific failure value.
Axial.Process.ProcessResultThe complete structured transcript returned by a process execution.
Axial.Process.ProcessErrorA recoverable process startup, timeout, stage, or I/O failure. Interrupting the workflow is not an error: it terminates the processes and surfaces as <c>Cause.Interrupt</c>.
FailureThe workflow failed due to a specific cause.
Axial.Cause`1Represents the cause of a failed workflow. The type of the domain-specific failure value.
FailAn expected domain-specific failure.
StartFailedfailure: ProcessStartFailureTimedOutfailure: ProcessTimeoutStageFailedfailure: StageFailureProcess.command $"sh -c 'exit 3'" |> Process.toFlow |> Flow.run host |> explain |> shouldEqual "stage 0 exited 3"
Process.command $"no-such-command-axial-docs" |> Process.toFlow |> Flow.run host |> explain |> shouldEqual "could not start no-such-command-axial-docs"
Axial.Process.ProcessModulecommand: FormattableString -> ProcessSpecCreates a safely tokenized one-command process specification from an interpolated command template. Each interpolation hole is one native argument. Example: Process.command $"git show {revision}" |> Process.toFlow
(|>): 'T1 -> ('T1 -> 'U) -> 'UApply a function to a value, the value being on the left, the function on the right The argument. The function. The function result. let doubleIt x = x * 2 3 |> doubleIt // Evaluates to 6
toFlow: ProcessSpec -> Flow<'env,ProcessError,ProcessResult>Converts a process specification into a lazy Flow in the current environment. Example: specification |> Process.toFlow
Axial.Flowrun: 'env -> Flow<'env,'error,'value> -> Exit<'value,'error>Runs the workflow and blocks until the final exit is available. The environment used by the workflow. The workflow to run. The final workflow exit. let exit = workflow |> Flow.run environment
host: ProcessHostEnvironmentexplain: Exit<ProcessResult,ProcessError> -> stringshouldEqual: 'a -> 'a -> unitProcessError.describe formats a redacted diagnostic.
ProcessError.exitCode maps a failed stage to its native exit code, timeout
to 124, cancellation to 130, and startup or I/O failure to 1. The host run applies the
same mapping automatically.
What a successful result contains
A ProcessResult is returned only when every stage satisfies its success policy. It contains the final stdout and
stderr text, exact captured bytes, every stage's exit code, start times, durations, and bounded stderr tails. Change
Process.successCodes when a command treats other exit codes as successful.
let stageSummary (specification: ProcessSpec) : Flow<ProcessHostEnvironment, ProcessError, string list> =
flow {
let! result = specification |> Process.toFlow
return [ for stage in result.Stages -> $"[{stage.Stage}] {stage.Command} => {stage.ExitCode}" ]
}
stageSummary: ProcessSpec -> Flow<ProcessHostEnvironment,ProcessError,string list>specification: ProcessSpecAxial.Process.ProcessSpecAn immutable description of one command or a connected process topology and its execution policy.
Axial.Flow`3Represents a cold workflow that reads an environment, returns a typed result, and is executed explicitly through one of its execution members such as ToTask, ToAsync, or RunSynchronously. The type of the environment dependency. The type of the failure value. The type of the success value.
Axial.Process.ProcessHostEnvironmentThe live environment used by <c>Process.run</c> at a command-line host boundary. Application workflows normally use their own environment record and <c>Process.runWith</c>.
Axial.Process.ProcessErrorA recoverable process startup, timeout, stage, or I/O failure. Interrupting the workflow is not an error: it terminates the processes and surfaces as <c>Cause.Interrupt</c>.
stringAn abbreviation for the CLI type . Basic Types
listThe type of immutable singly-linked lists. See the module for further operations related to lists. Use the constructors [] and :: (infix) to create values of this type, or the notation [1; 2; 3]. Use the values in the List module to manipulate values of this type, or pattern match against the values directly. See also F# Language Guide - Lists.
flow: FlowBuilderThe universal flow { } computation expression.
result: ProcessResult(|>): 'T1 -> ('T1 -> 'U) -> 'UApply a function to a value, the value being on the left, the function on the right The argument. The function. The function result. let doubleIt x = x * 2 3 |> doubleIt // Evaluates to 6
Axial.Process.ProcessModuletoFlow: ProcessSpec -> Flow<'env,ProcessError,ProcessResult>Converts a process specification into a lazy Flow in the current environment. Example: specification |> Process.toFlow
stage: StageResultStages: StageResult listProcess.command $"printf 'a\nb\n'" |> Process.pipe (Process.command $"wc -l")
|> stageSummary
|> Flow.run host
|> shouldEqual (Exit.Success [ "[0] printf 'a\nb\n' => 0"; "[1] wc -l => 0" ])
Axial.Process.ProcessModulecommand: FormattableString -> ProcessSpecCreates a safely tokenized one-command process specification from an interpolated command template. Each interpolation hole is one native argument. Example: Process.command $"git show {revision}" |> Process.toFlow
(|>): 'T1 -> ('T1 -> 'U) -> 'UApply a function to a value, the value being on the left, the function on the right The argument. The function. The function result. let doubleIt x = x * 2 3 |> doubleIt // Evaluates to 6
pipe: ProcessSpec -> ProcessSpec -> ProcessSpecConnects the current stdout to the next one-command specification's stdin.
stageSummary: ProcessSpec -> Flow<ProcessHostEnvironment,ProcessError,string list>Axial.Flowrun: 'env -> Flow<'env,'error,'value> -> Exit<'value,'error>Runs the workflow and blocks until the final exit is available. The environment used by the workflow. The workflow to run. The final workflow exit. let exit = workflow |> Flow.run environment
host: ProcessHostEnvironmentshouldEqual: 'a -> 'a -> unitAxial.Exit`2Represents the final outcome of a workflow execution. The type of the success value. The type of the domain-specific failure value.
SuccessThe workflow completed successfully.

