@@ -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
3334supervise a program and, for example, restart it in case it exists with an error. Or startup dependencies like start a
3435webserver 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
0 commit comments