Skip to content

Commit 11b2bf9

Browse files
committed
Update readme and documentation
1 parent be2069e commit 11b2bf9

File tree

2 files changed

+128
-131
lines changed

2 files changed

+128
-131
lines changed

README.md

Lines changed: 114 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@ inside containers.
1515

1616
## Goals
1717

18-
* **Supervision**: A fully-featured supervision system, designed to be run in containers (but not exclusively).
19-
* **Simplicity**: Clear, modifiable, and removable code as needed.
20-
* **Completeness**: A seamless drop-in for any `init` system.
21-
* **Reliability**: Stability and trustworthiness across all use cases.
18+
* **Supervision**: A fully-featured supervisor system, easy to use and designed to be run in containers (but not
19+
exclusively).
20+
* **Simplicity**: Simple to use and simple to modify.
21+
* **Completeness**: A seamless drop-in for any `init` or supervisor system.
22+
* **Reliability**: Written using safe and correct wrappers.
2223

2324
## Status
2425

@@ -33,171 +34,159 @@ Being a supervision and init system, it can be used to start and manage a bunch
3334
supervise a program and, for example, restart it in case it exists with an error. Or startup dependencies like start a
3435
webserver after starting a database.
3536

36-
## Quick tutorial
37-
38-
As a simple example, assume you'd like to host your rest api. This is the code:
37+
Keep scrolling for a quick tutorial or check out the [documentation](https://gh.fponzi.me/Horust) for a complete
38+
reference of the options available on the
39+
service config file.
3940

40-
```
41-
from http.server import BaseHTTPRequestHandler, HTTPServer
42-
43-
class Handler(BaseHTTPRequestHandler):
44-
def do_GET(self):
45-
if self.path == "/user":
46-
raise Exception("Unsupported path: /user") # Exception will kill the server
47-
self.send_response(200)
48-
self.send_header("Content-type", "text/plain")
49-
self.end_headers()
50-
self.wfile.write(b"Hello, World!")
51-
52-
HTTPServer(('', 8000), Handler).serve_forever()
53-
```
41+
This is a quick overview:
5442

55-
you can run it using `python3 myapp.py`. If you go to localhost:8000/user, unfortunately, the server will fail. Now you
56-
need to manually restart it!
43+
```toml
44+
command = "/bin/bash -c 'echo hello world'"
45+
start-delay = "2s"
46+
start-after = ["database", "backend.toml"]
47+
stdout = "STDOUT"
48+
stdout-rotate-size = "100MB"
49+
stdout-should-append-timestamp-to-filename = false
50+
stderr = "/var/logs/hello_world_svc/stderr.log"
51+
user = "root"
52+
working-directory = "/tmp/"
5753

58-
Let's see how we can use horust to supervise it and restart it in case of failure.
54+
[restart]
55+
strategy = "never"
56+
backoff = "0s"
57+
attempts = 0
5958

60-
#### 1. Create your first Horust service:
59+
[healthiness]
60+
http-endpoint = "http://localhost:8080/healthcheck"
61+
file-path = "/var/myservice/up"
62+
command = "curl -s localhost:8080/healthcheck"
6163

62-
> [!TIP]
63-
> You can also bootstrap the creation of a new service, by using `horust --sample-service > new_service.toml`.
64+
[failure]
65+
successful-exit-code = [0, 1, 255]
66+
strategy = "ignore"
6467

65-
We are now going to create a new config file for our service. They are defined
66-
in [TOML](https://github.com/toml-lang/toml) and the default path where horust will look for service is in
67-
`/etc/horust/services/`.
68+
[termination]
69+
signal = "TERM"
70+
wait = "10s"
71+
die-if-failed = ["db.toml"]
6872

69-
> [!NOTE]
70-
> It's possible to run a one-shot instance just by doing `horust myprogram` without defining a service config file.
73+
[environment]
74+
keep-env = false
75+
re-export = ["PATH", "DB_PASS"]
76+
additional = { key = "value" }
7177

72-
Let's create a new service under `/etc/horust/services/healthchecker.toml`:
78+
[resource-limit]
79+
cpu = 0.5
80+
memory = "100 MiB"
81+
pids-max = 100
82+
```
7383

74-
```toml
75-
command = "/tmp/myapp.py"
76-
[restart]
77-
strategy = "always"
78-
```
84+
## How to get started with Horust:
7985

80-
There are many [_supported_](https://github.com/FedericoPonzi/Horust/blob/master/DOCUMENTATION.md) properties for your
81-
service file, but only `command` is _required_.
86+
You can grab the latest release from the [releases](https://github.com/FedericoPonzi/Horust/releases/) page. If you
87+
like to live on the edge, scroll down to the building section.
8288

83-
On startup, Horust will read this service file, and run the `command` after waiting for 10 seconds. According to the
84-
restart strategy "`never`", as
85-
soon as the service has carried out its task it will restart.
89+
There are docker releases:
8690

87-
As you can see, it will run the `/tmp/myapp.py` Python script, which doesn't exist yet. Let's create it!
91+
* Github: https://github.com/FedericoPonzi/Horust/pkgs/container/horust
92+
* Dockerhub: https://hub.docker.com/r/federicoponzi/horust
8893

89-
#### 2. Create your app:
94+
You can also pull horust as a library from [crates.io](https://crates.io/crates/horust), or use cargo to
95+
install it:
9096

91-
Create a new file script under `/tmp/myapp.py`:
97+
```
98+
cargo install horust
99+
```
92100

93-
```python
94-
#!/usr/bin/env python3
95-
from http.server import BaseHTTPRequestHandler, HTTPServer
101+
## Horustctl:
96102

97-
class Handler(BaseHTTPRequestHandler):
98-
def do_GET(self):
99-
if self.path == "/user":
100-
raise Exception("Unsupported path: /user") # Exception will kill the server
101-
self.send_response(200)
102-
self.send_header("Content-type", "text/plain")
103-
self.end_headers()
104-
self.wfile.write(b"Hello, World!")
103+
Horustctl is a program that allows you to interact with horust. They communicate using Unix Domain Socket (UDS), and by
104+
default, horust stores the sockets in /var/run/horust. You can override the path by using the argument
105+
--uds-folder-path. Then you can use it like this:
105106

106-
HTTPServer(('', 8000), Handler).serve_forever()
107+
```
108+
horustctl --uds-folder-path /tmp status myapp.toml
107109
```
108110

109-
And remember to make it executable:
111+
To check the status of your service. Currently, horustctl only supports querying for the service status.
110112

111-
```shell
112-
chmod +x /tmp/api.py
113-
```
113+
## Quick tutorial
114114

115-
#### 3. Get the latest release or build from source:
115+
### Problem:
116116

117-
You can grab the latest release from the [releases](https://github.com/FedericoPonzi/Horust/releases/) page. Or if you
118-
like to live on the edge, scroll down to the building section.
117+
Assume you have a container in which you want to run a database and a monitoring system. The database should be started
118+
first, and the monitoring system should be started only after the database is up.
119119

120-
#### 4. Run Horust:
120+
A container can spin up a single process, so you create a simple bash file to handle the dependency.
121+
Then, if the monitoring system fails or the database fails, you want to restart it. While you figure the different
122+
requirements, your simple bash script keeps growing.
121123

122-
Now you can just:
124+
Let's see how we can use horust to spin up the two services and monitor them.
123125

124-
```shell
125-
./horust --uds-folder-path /tmp
126-
```
126+
### 1. Create your first Horust service:
127127

128128
> [!TIP]
129-
> Horustctl is a program that allows you to interact with horust. They communicate using Unix Domain Socket (UDS),
130-
> and by default horust stores the sockets in `/var/run/horust`.
131-
> In this example, we have overridden the path by using the argument `--uds-folder-path`.
129+
> You can also bootstrap the creation of a new service, by using `horust --sample-service > new_service.toml`.
130+
131+
Each program we need to spin up has its own service config file. They are defined
132+
in [TOML](https://github.com/toml-lang/toml) and the default path where horust will look for service is in
133+
`/etc/horust/services/`.
132134

133-
Try navigating to `http://localhost:8000/`. A page with Hello world
134-
should be greeting you.
135+
> [!NOTE]
136+
> It's possible to run a one-shot instance just by doing `horust myprogram` without defining a service config file.
135137
136-
Now try navigating to `http://localhost:8000/user` - you should get a "the connection was reset" error page.
137-
Checking on your terminal, you will see that the program has raised the exception, as we expected. Now, try navigating
138-
again to `http://localhost:8000/` and the website is still up and running.
138+
Let's create a new service under `/etc/horust/services/database.toml`:
139139

140-
Pretty nice uh? One last thing!
140+
```toml
141+
command = "python3 /opt/db/my-cool-database.py --bind 0.0.0.0 --port 5323"
142+
start-delay = "2s"
143+
[restart]
144+
strategy = "always"
145+
```
141146

142-
If you downloaded a copy of horustctl, you can also do:
147+
and another service for the monitoring: `/etc/horust/services/monitoring.toml`:
143148

144-
```
145-
horustctl --uds-folder-path /tmp status myapp.toml
149+
```toml
150+
command = "python3 /opt/db/monitoring.py --port 5323"
151+
start-after = ["database.toml"]
152+
working-directory = "/tmp/"
146153
```
147154

148-
To check the status of your service. Currently, horustctl only support querying for the service status.
155+
There are many [_supported_](https://gh.fponzi.me/Horust) properties for your
156+
service file, but only `command` is _required_.
149157

150-
### 5. Wrapping up
158+
On startup, Horust will read this service file. According to the restart strategy "`never`", as
159+
soon as the service has carried out its task it will restart.
151160

152-
Use <kbd>Ctrl</kbd>+<kbd>C</kbd> to stop Horust. Horust will send a `SIGTERM` signal to all the running services, and if
153-
it doesn't hear back for a while - it will terminate them by sending an additional `SIGKILL` signal. Wait time and
154-
signals are configurable.
161+
As you can see, it will run the `/tmp/myapp.py` Python script, which doesn't exist yet. Let's create it!
155162

156-
---
163+
### 2. Define your container:
157164

158-
Check out the [documentation](https://github.com/FedericoPonzi/Horust/blob/master/DOCUMENTATION.md) for a complete
159-
reference of the options available on the service config file. A general overview is available below as well:
165+
```dockerfile
166+
FROM federicoponzi/horust:v0.2.0
167+
# Install dependencies for my cool db
168+
RUN apt-get update && \
169+
apt-get install -y python3 python3-pip && \
170+
pip3 install requests
160171

161-
```toml
162-
command = "/bin/bash -c 'echo hello world'"
163-
start-delay = "2s"
164-
start-after = ["database", "backend.toml"]
165-
stdout = "STDOUT"
166-
stdout-rotate-size = "100MB"
167-
stdout-should-append-timestamp-to-filename = false
168-
stderr = "/var/logs/hello_world_svc/stderr.log"
169-
user = "root"
170-
working-directory = "/tmp/"
172+
COPY db /opt/db/
171173

172-
[restart]
173-
strategy = "never"
174-
backoff = "0s"
175-
attempts = 0
174+
# Copy Horust service definition into the container
175+
COPY database.toml /etc/horust/services/
176+
COPY monitoring.toml /etc/horust/services/
176177

177-
[healthiness]
178-
http-endpoint = "http://localhost:8080/healthcheck"
179-
file-path = "/var/myservice/up"
180-
command = "curl -s localhost:8080/healthcheck"
181-
182-
[failure]
183-
successful-exit-code = [0, 1, 255]
184-
strategy = "ignore"
178+
# Set entrypoint to Horust
179+
ENTRYPOINT ["/sbin/horust"]
180+
```
185181

186-
[termination]
187-
signal = "TERM"
188-
wait = "10s"
189-
die-if-failed = ["db.toml"]
182+
and we're ready to start our container: `docker build -t my-cool-db .` and
183+
`docker run -it --rm --name my-cool-db my-cool-db`.
190184

191-
[environment]
192-
keep-env = false
193-
re-export = ["PATH", "DB_PASS"]
194-
additional = { key = "value" }
185+
### 3. Terminate the container
195186

196-
[resource-limit]
197-
cpu = 0.5
198-
memory = "100 MiB"
199-
pids-max = 100
200-
```
187+
Use <kbd>Ctrl</kbd>+<kbd>C</kbd> to stop Horust. Horust will send a `SIGTERM` signal to all the running services, and if
188+
it doesn't hear back for a while - it will terminate them by sending an additional `SIGKILL` signal. Wait time and
189+
signals are configurable.
201190

202191
## Building
203192

docs/README.md

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
- [Horust's configuration](#horusts-configuration)
1818
- [Running a single command](#running-a-single-command)
1919
- [Multiple service directories](#multiple-service-directories)
20+
- [horustctl: Checking system status](#horustctl-checking-system-status)
2021
- [Plugins (WIP)](#plugins-wip)
21-
- [Checking system status (WIP)](#checking-system-status-wip)
2222

2323
When starting horust, you can optionally specify where it should look for services and uses `/etc/horust/services` by
2424
default.
@@ -311,13 +311,21 @@ These directories are loaded at once and treated just like all `*.toml` files we
311311
It means that for example service from `./services/extra` can depend on service from `./services/core`.
312312
The last parameter is used to load a single service file instead of a directory.
313313

314+
## horustctl: Checking system status
315+
316+
Horustctl is a program that allows you to interact with horust. They communicate using Unix Domain Socket (UDS), and by
317+
default, horust stores the sockets in /var/run/horust. You can override the path by using the argument
318+
--uds-folder-path. Then you can use it, like this:
319+
320+
```
321+
horustctl --uds-folder-path /tmp status myapp.toml
322+
```
323+
324+
To check the status of your service. Currently, horustctl only supports querying for the service status. Additional
325+
capabilities are planned but not yet implemented.
326+
314327
## Plugins (WIP)
315328

316329
Horust works via message passing, it should be fairly easy to plug additional components connected to its bus.
317330
At this time is unclear if there is the need for this. Please raise an issue if you're interested in seeing this
318331
feature.
319-
320-
## Checking system status (WIP)
321-
322-
WIP: https://github.com/FedericoPonzi/Horust/issues/31
323-
The idea is to create another binary, which will somehow report the system status. A `systemctl` for Horust.

0 commit comments

Comments
 (0)