Changeset View
Changeset View
Standalone View
Standalone View
src/docs/user/field/exit_codes.diviner
@title Command Line Exit Codes | @title Command Line Exit Codes | ||||
@group fieldmanual | @group fieldmanual | ||||
Explains the use of exit codes in Phabricator command line scripts. | Explains the use of exit codes in Phorge command line scripts. | ||||
Overview | Overview | ||||
======== | ======== | ||||
When you run a command from the command line, it exits with an //exit code//. | When you run a command from the command line, it exits with an //exit code//. | ||||
This code is normally not shown on the CLI, but you can examine the exit code | This code is normally not shown on the CLI, but you can examine the exit code | ||||
of the last command you ran by looking at `$?` in your shell: | of the last command you ran by looking at `$?` in your shell: | ||||
$ ls | $ ls | ||||
... | ... | ||||
$ echo $? | $ echo $? | ||||
0 | 0 | ||||
Programs which run commands can operate on exit codes, and shell constructs | Programs which run commands can operate on exit codes, and shell constructs | ||||
like `cmdx && cmdy` operate on exit codes. | like `cmdx && cmdy` operate on exit codes. | ||||
The code `0` means success. Other codes signal some sort of error or status | The code `0` means success. Other codes signal some sort of error or status | ||||
condition, depending on the system and command. | condition, depending on the system and command. | ||||
With rare exception, Phabricator uses //all other codes// to signal | With rare exception, Phorge uses //all other codes// to signal | ||||
**catastrophic failure**. | **catastrophic failure**. | ||||
This is an explicit architectural decision and one we are unlikely to deviate | This is an explicit architectural decision and one we are unlikely to deviate | ||||
from: generally, we will not accept patches which give a command a nonzero exit | from: generally, we will not accept patches which give a command a nonzero exit | ||||
code to indicate an expected state, an application status, or a minor abnormal | code to indicate an expected state, an application status, or a minor abnormal | ||||
condition. | condition. | ||||
Generally, this decision reflects a philosophical belief that attaching | Generally, this decision reflects a philosophical belief that attaching | ||||
application semantics to exit codes is a relic of a simpler time, and that | application semantics to exit codes is a relic of a simpler time, and that | ||||
they are not appropriate for communicating application state in a modern | they are not appropriate for communicating application state in a modern | ||||
operational environment. This document explains the reasoning behind our use of | operational environment. This document explains the reasoning behind our use of | ||||
exit codes in more detail. | exit codes in more detail. | ||||
In particular, this approach is informed by a focus on operating Phabricator | In particular, this approach is informed by a focus on operating Phorge | ||||
clusters at scale. This is not a common deployment scenario, but we consider it | clusters at scale. This is not a common deployment scenario, but we consider it | ||||
the most important one. Our use of exit codes makes it easier to deploy and | the most important one. Our use of exit codes makes it easier to deploy and | ||||
operate a Phabricator cluster at larger scales. It makes it slightly harder to | operate a Phorge cluster at larger scales. It makes it slightly harder to | ||||
deploy and operate a small cluster or single host by gluing together `bash` | deploy and operate a small cluster or single host by gluing together `bash` | ||||
scripts. We are willingly trading the small scale away for advantages at larger | scripts. We are willingly trading the small scale away for advantages at larger | ||||
scales. | scales. | ||||
Problems With Exit Codes | Problems With Exit Codes | ||||
======================== | ======================== | ||||
We do not use exit codes to communicate application state because doing so | We do not use exit codes to communicate application state because doing so | ||||
makes it harder to write correct scripts, and the primary benefit is that it | makes it harder to write correct scripts, and the primary benefit is that it | ||||
makes it easier to write incorrect ones. | makes it easier to write incorrect ones. | ||||
This is somewhat at odds with the philosophy of "worse is better", but a modern | This is somewhat at odds with the philosophy of "worse is better", but a modern | ||||
operations environment faces different forces than the interactive shell did | operations environment faces different forces than the interactive shell did | ||||
in the 1970s, particularly at scale. | in the 1970s, particularly at scale. | ||||
We consider correctness to be very important to modern operations environments. | We consider correctness to be very important to modern operations environments. | ||||
In particular, we manage a Phabricator cluster (Phacility) and believe that | In particular, we believe that having reliable, repeatable processes for | ||||
having reliable, repeatable processes for provisioning, configuration and | provisioning, configuration and deployment is critical to maintaining and | ||||
deployment is critical to maintaining and scaling our operations. Our use of | scaling our operations. Our use of exit codes makes it easier to implement | ||||
exit codes makes it easier to implement processes that are correct and reliable | processes that are correct and reliable on top of Phorge management scripts. | ||||
on top of Phabricator management scripts. | |||||
Exit codes as signals for application state are problematic because they are | Exit codes as signals for application state are problematic because they are | ||||
ambiguous: you can't use them to distinguish between dissimilar failure states | ambiguous: you can't use them to distinguish between dissimilar failure states | ||||
which should prompt very different operational responses. | which should prompt very different operational responses. | ||||
Exit codes primarily make writing things like `bash` scripts easier, but we | Exit codes primarily make writing things like `bash` scripts easier, but we | ||||
think you shouldn't be writing `bash` scripts in a modern operational | think you shouldn't be writing `bash` scripts in a modern operational | ||||
environment if you care very much about your software working. | environment if you care very much about your software working. | ||||
▲ Show 20 Lines • Show All 151 Lines • ▼ Show 20 Lines | |||||
Given these concerns, we are generally unwilling to bring changes which use | Given these concerns, we are generally unwilling to bring changes which use | ||||
exit codes to communicate application state (other than catastrophic failure) | exit codes to communicate application state (other than catastrophic failure) | ||||
into the upstream. There are some exceptions, but these are rare. In | into the upstream. There are some exceptions, but these are rare. In | ||||
particular, ease of use in a `bash` environment is not a compelling motivation. | particular, ease of use in a `bash` environment is not a compelling motivation. | ||||
We are broadly willing to make output machine parseable or provide an explicit | We are broadly willing to make output machine parseable or provide an explicit | ||||
machine output mode (often a `--json` flag) if there is a reasonable use case | machine output mode (often a `--json` flag) if there is a reasonable use case | ||||
for it. However, we operate a large production cluster of Phabricator instances | for it. However, we operate a large production cluster of Phorge instances | ||||
with the tools available in the upstream, so the lack of machine parseable | with the tools available in the upstream, so the lack of machine parseable | ||||
output is not sufficient to motivate adding such output on its own: we also | output is not sufficient to motivate adding such output on its own: we also | ||||
need to understand the problem you're facing, and why it isn't a problem we | need to understand the problem you're facing, and why it isn't a problem we | ||||
face. A simpler or cleaner approach to the problem may already exist. | face. A simpler or cleaner approach to the problem may already exist. | ||||
If you just want to write `bash` scripts on top of Phabricator scripts and you | If you just want to write `bash` scripts on top of Phorge scripts and you | ||||
are unswayed by these concerns, you can often just build a composite command to | are unswayed by these concerns, you can often just build a composite command to | ||||
get roughly the same effect that you'd get out of an exit code. | get roughly the same effect that you'd get out of an exit code. | ||||
For example, you can pipe things to `grep` to convert output into exit codes. | For example, you can pipe things to `grep` to convert output into exit codes. | ||||
This should generally have failure rates that are comparable to the background | This should generally have failure rates that are comparable to the background | ||||
failure level of relying on `bash` as a scripting environment. | failure level of relying on `bash` as a scripting environment. |
Content licensed under Creative Commons Attribution-ShareAlike 4.0 (CC-BY-SA) unless otherwise noted; code licensed under Apache 2.0 or other open source licenses. · CC BY-SA 4.0 · Apache 2.0