{"id":13595092,"url":"https://github.com/FedericoPonzi/Horust","last_synced_at":"2025-04-09T10:32:46.535Z","repository":{"id":36957846,"uuid":"232196110","full_name":"FedericoPonzi/Horust","owner":"FedericoPonzi","description":"Horust is a supervisor / init system written in rust and designed to run inside containers.","archived":false,"fork":false,"pushed_at":"2025-03-26T09:18:32.000Z","size":1218,"stargazers_count":199,"open_issues_count":16,"forks_count":20,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-08T00:34:31.045Z","etag":null,"topics":["docker","init","init-system","operating-system","rust","rust-lang","supervisor"],"latest_commit_sha":null,"homepage":"https://gh.fponzi.me/Horust/","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/FedericoPonzi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-01-06T22:23:03.000Z","updated_at":"2025-04-07T12:25:01.000Z","dependencies_parsed_at":"2024-01-14T16:07:47.366Z","dependency_job_id":"212c7440-726d-411c-ad0a-ec62ea106b36","html_url":"https://github.com/FedericoPonzi/Horust","commit_stats":{"total_commits":354,"total_committers":9,"mean_commits":"39.333333333333336","dds":0.3192090395480226,"last_synced_commit":"07b5a02b3c9b0a448c0099fbf0b6e145a8734235"},"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FedericoPonzi%2FHorust","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FedericoPonzi%2FHorust/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FedericoPonzi%2FHorust/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FedericoPonzi%2FHorust/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/FedericoPonzi","download_url":"https://codeload.github.com/FedericoPonzi/Horust/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248020593,"owners_count":21034459,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["docker","init","init-system","operating-system","rust","rust-lang","supervisor"],"created_at":"2024-08-01T16:01:43.859Z","updated_at":"2025-04-09T10:32:46.528Z","avatar_url":"https://github.com/FedericoPonzi.png","language":"Rust","readme":"[\u003cimg src=\"https://github.com/FedericoPonzi/Horust/raw/master/res/horust-logo.png\" width=\"300\" align=\"center\"\u003e](https://github.com/FedericoPonzi/Horust/raw/master/res/horust-logo.png)\n\n[![CI](https://github.com/FedericoPonzi/horust/workflows/CI/badge.svg?branch=master\u0026event=push)](https://github.com/FedericoPonzi/Horust/actions?query=workflow%3ACI) [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)\n\n[Horust](https://github.com/FedericoPonzi/Horust) is a supervisor / init system written in rust and designed to be run\ninside containers.\n\n# Table of contents\n\n* [Goals](#goals)\n* [Status](#status)\n* [Usage](#usage)\n* [Contributing](#contributing)\n* [License](#license)\n\n## Goals\n\n* **Supervision**: A fully-featured supervision system, designed to be run in containers (but not exclusively).\n* **Simplicity**: Clear, modifiable, and removable code as needed.\n* **Completeness**: A seamless drop-in for any `init` system.\n* **Reliability**: Stability and trustworthiness across all use cases.\n\n## Status\n\nThis should be considered Beta software. You can (and should) use it, but under your own\ndiscretion. Please report any issue you encounter, or also sharing your use cases would be very helpful.\nHorust can be used on macOS in development situations. Due to limitations in the macOS API, subprocesses of supervised\nprocesses may not correctly be reaped when their parent process exits.\n\n## Usage\n\nBeing a supervision and init system, it can be used to start and manage a bunch of processes. You can use it to\nsupervise a program and, for example, restart it in case it exists with an error. Or startup dependencies like start a\nwebserver after starting a database.\n\n## Quick tutorial\n\nAs a simple example, assume you'd like to host your rest api. This is the code:\n\n```\nfrom http.server import BaseHTTPRequestHandler, HTTPServer\n\nclass Handler(BaseHTTPRequestHandler):\n    def do_GET(self):\n         if self.path == \"/user\":\n            raise Exception(\"Unsupported path: /user\")  # Exception will kill the server\n        self.send_response(200)\n        self.send_header(\"Content-type\", \"text/plain\")\n        self.end_headers()\n        self.wfile.write(b\"Hello, World!\")\n\nHTTPServer(('', 8000), Handler).serve_forever()\n```\n\nyou can run it using `python3 myapp.py`. If you go to localhost:8000/user, unfortunately, the server will fail. Now you\nneed to manually restart it!\n\nLet's see how we can use horust to supervise it and restart it in case of failure.\n\n#### 1. Create your first Horust service:\n\n\u003e [!TIP]\n\u003e You can also bootstrap the creation of a new service, by using `horust --sample-service \u003e new_service.toml`.\n\nWe are now going to create a new config file for our service. They are defined\nin [TOML](https://github.com/toml-lang/toml) and the default path where horust will look for service is in\n`/etc/horust/services/`.\n\n\u003e [!NOTE]\n\u003e It's possible to run a one-shot instance just by doing `horust myprogram` without defining a service config file.\n\nLet's create a new service under `/etc/horust/services/healthchecker.toml`:\n\n```toml\ncommand = \"/tmp/myapp.py\"\n[restart]\nstrategy = \"always\"\n``` \n\nThere are many [_supported_](https://github.com/FedericoPonzi/Horust/blob/master/DOCUMENTATION.md) properties for your\nservice file, but only `command` is _required_.\n\nOn startup, Horust will read this service file, and run the `command` after waiting for 10 seconds. According to the\nrestart strategy \"`never`\", as\nsoon as the service has carried out its task it will restart.\n\nAs you can see, it will run the `/tmp/myapp.py` Python script, which doesn't exist yet. Let's create it!\n\n#### 2. Create your app:\n\nCreate a new file script under `/tmp/myapp.py`:\n\n```python\n#!/usr/bin/env python3\nfrom http.server import BaseHTTPRequestHandler, HTTPServer\n\nclass Handler(BaseHTTPRequestHandler):\n    def do_GET(self):\n        if self.path == \"/user\":\n            raise Exception(\"Unsupported path: /user\")  # Exception will kill the server\n        self.send_response(200)\n        self.send_header(\"Content-type\", \"text/plain\")\n        self.end_headers()\n        self.wfile.write(b\"Hello, World!\")\n\nHTTPServer(('', 8000), Handler).serve_forever()\n```\n\nAnd remember to make it executable:\n\n```shell\nchmod +x /tmp/api.py\n```\n\n#### 3. Get the latest release or build from source:\n\nYou can grab the latest release from the [releases](https://github.com/FedericoPonzi/Horust/releases/) page. Or if you\nlike to live on the edge, scroll down to the building section.\n\n#### 4. Run Horust:\n\nNow you can just:\n\n```shell\n./horust --uds-folder-path /tmp\n```\n\n\u003e [!TIP]\n\u003e Horustctl is a program that allows you to interact with horust. They communicate using Unix Domain Socket (UDS),\n\u003e and by default horust stores the sockets in `/var/run/horust`.\n\u003e In this example, we have overridden the path by using the argument `--uds-folder-path`.\n\nTry navigating to `http://localhost:8000/`. A page with Hello world\nshould be greeting you.\n\nNow try navigating to `http://localhost:8000/user` - you should get a \"the connection was reset\" error page.\nChecking on your terminal, you will see that the program has raised the exception, as we expected. Now, try navigating\nagain to `http://localhost:8000/` and the website is still up and running.\n\nPretty nice uh? One last thing!\n\nIf you downloaded a copy of horustctl, you can also do:\n\n```\nhorustctl --uds-folder-path /tmp status myapp.toml\n```\n\nTo check the status of your service. Currently, horustctl only support querying for the service status.\n\n### 5. Wrapping up\n\nUse \u003ckbd\u003eCtrl\u003c/kbd\u003e+\u003ckbd\u003eC\u003c/kbd\u003e to stop Horust. Horust will send a `SIGTERM` signal to all the running services, and if\nit doesn't hear back for a while - it will terminate them by sending an additional  `SIGKILL` signal. Wait time and\nsignals are configurable.\n\n---\n\nCheck out the [documentation](https://github.com/FedericoPonzi/Horust/blob/master/DOCUMENTATION.md) for a complete\nreference of the options available on the service config file. A general overview is available below as well:\n\n```toml\ncommand = \"/bin/bash -c 'echo hello world'\"\nstart-delay = \"2s\"\nstart-after = [\"database\", \"backend.toml\"]\nstdout = \"STDOUT\"\nstdout-rotate-size = \"100MB\"\nstdout-should-append-timestamp-to-filename = false\nstderr = \"/var/logs/hello_world_svc/stderr.log\"\nuser = \"root\"\nworking-directory = \"/tmp/\"\n\n[restart]\nstrategy = \"never\"\nbackoff = \"0s\"\nattempts = 0\n\n[healthiness]\nhttp-endpoint = \"http://localhost:8080/healthcheck\"\nfile-path = \"/var/myservice/up\"\ncommand = \"curl -s localhost:8080/healthcheck\"\n\n[failure]\nsuccessful-exit-code = [0, 1, 255]\nstrategy = \"ignore\"\n\n[termination]\nsignal = \"TERM\"\nwait = \"10s\"\ndie-if-failed = [\"db.toml\"]\n\n[environment]\nkeep-env = false\nre-export = [\"PATH\", \"DB_PASS\"]\nadditional = { key = \"value\" }\n\n[resource-limit]\ncpu = 0.5\nmemory = \"100 MiB\"\npids-max = 100\n```\n\n## Building\n\nFor building Horust, you will need [Rust](https://www.rust-lang.org/learn/get-started) and `protoc` compiler. Protoc is\nused for interacting with horust through horustctl.\nAs soon as both are installed, you can build Horust with:\n\n```shell\ncargo build --release\n```\n\n## Contributing\n\nThanks for considering contributing to horust! To get started, have a look\nat [CONTRIBUTING.md](https://github.com/FedericoPonzi/Horust/blob/master/CONTRIBUTING.md).\n\n## License\n\nHorust is provided under the MIT license. Please read the\nattached [license](https://github.com/FedericoPonzi/horust/blob/master/LICENSE) file.\n","funding_links":[],"categories":["Rust","docker"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FFedericoPonzi%2FHorust","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FFedericoPonzi%2FHorust","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FFedericoPonzi%2FHorust/lists"}