# Quick demo
## Instructions
1. [Install Arpx on your machine](https://github.com/jaredgorski/arpx#installing).
2. Create a new file somewhere on your computer called `arpx_demo.yaml`.
3. In `arpx_demo.yaml`, paste this text:
```yaml
jobs:
foo: |
bar ? baz : qux;
[
bar;
baz;
qux;
]
bar; @quux
processes:
bar:
command: echo bar
baz:
command: echo baz
qux:
command: echo qux
quux:
command: echo quux
log_monitors:
quux:
buffer_size: 1
test: 'echo "$ARPX_BUFFER" | grep -q "bar"' # or equivalent for your system
ontrigger: quux
```
4. In your terminal, execute:
```terminal
arpx -f /path/to/arpx_demo.yaml -j foo
```
5. If you did everything right, you should see _something like_ the following output in your terminal:
```terminal
[bar] "bar" (1) spawned
[bar] bar
[bar] "bar" (1) succeeded
[bar] "baz" (2) spawned
[bar] baz
[bar] "baz" (2) succeeded
[bar] "bar" (3) spawned
[baz] "baz" (4) spawned
[qux] "qux" (5) spawned
[bar] bar
[baz] baz
[qux] qux
[bar] "bar" (3) succeeded
[baz] "baz" (4) succeeded
[qux] "qux" (5) succeeded
[bar] "bar" (6) spawned
[bar] bar
[bar] "bar" (6) succeeded
[quux] "quux" (7) spawned
[quux] quux
[quux] "quux" (7) succeeded
```
## What did we just do?
Let's break this down.
Job `foo` contains three tasks:
1. `bar ? baz : qux;`
2. `[ bar; baz; qux; ]`
3. `bar; @quux`
### Task 1: contingency
```text
bar ? baz : qux;
```
The Arpx runtime can be programmed to respond to process exit statuses using ternary syntax. If the initial process succeeds, the `?` branch runs. If the initial process fails, the `:` branch runs. In this case, the runtime will execute `baz` when `bar` exits with a successful status.
Contingency only works on one level for now, so ternary operators can't be chained. Chaining will result in a parsing error.
### Task 2: concurrency
```text
[
bar;
baz;
qux;
]
```
Any given job in an Arpx runtime is composed of tasks. Each task represents one or more _concurrent_ processes. Multiple processes can be programmed into a single task by enclosing with square brackets. When more than one process is enclosed in square brackets, those processes will run simultaneously.
**Note:** Contingency and log monitor declarations can be included in each process declaration, so this is a valid task:
```text
[
bar ? baz;
qux : bar;
baz ? baz : qux; @quux;
]
```
### Task 3: a log monitor
```text
bar; @quux
```
This runtime job task contains a log monitor declaration (`@quux`). This means that the log monitor named `quux`, defined in the `log_monitors` mapping on the profile, will run concurrently with `bar` and watch its output, storing its most recent _n_ number of lines in a rolling buffer of _n_ size. The buffer size is set to `1` in this case, but it defaults to `20`.
With each update to the buffer, the log monitor will run its `test` script. The `test` script has access to a local environment variable called `ARPX_BUFFER` which it can use to string match for certain program conditions visible via the process logs. If the `test` script returns with a `0` status and there is an `ontrigger` action defined for the log monitor, the `ontrigger` action will be executed.
For example, a given process may log a 14 line long error message. A log monitor with a `buffer_size` of `14` can be used to match against that error message and respond to the error state during runtime. When the log monitor matches the error output, it will execute its `ontrigger` action. For a list of available actions, TODO.
Log monitors can be defined without an `ontrigger` action as well, in which case the log monitor will still execute the `test` script on each update to the buffer. This opens up the possibility of using log monitors to append external log files and otherwise respond to log states within the `test` script itself.
For example, the following log monitor exists solely to append process output to a log file:
```text
jobs:
job1: proc1; @mon1
...
log_monitors:
mon1:
buffer_size: 1
test: 'echo "$ARPX_BUFFER" >> /path/to/test.log'
```
### Putting it all together
When our profile is loaded and executed with Arpx, the following happens:
1. Task 1 begins. Process `bar` is executed and successfully exits.
2. Because `bar` exited successfully, the Arpx runtime executes `baz`. This concludes task 1.
3. Task 2 begins. Processes `bar`, `baz`, and `qux` are spawned simultaneously in separate threads.
4. `bar`, `baz`, and `qux` all exit successfully. This concludes task 2.
5. Task 3 begins. Process `bar` is spawned and the log monitor `quux` is spawned alongside it, receiving its output and storing it in a buffer.
6. `bar` logs "bar" to stdout and `quux` receives it, running its `test` script against the text. `test` exits successfully, so the Arpx runtime executes `quux`'s `ontrigger` action, which is a process also named `quux`.
7. Process `quux` is executed and successfully exits. This is the end of the Arpx runtime.