{"id":19541216,"url":"https://github.com/ysbaddaden/panzer","last_synced_at":"2026-03-09T08:32:38.068Z","repository":{"id":66263918,"uuid":"77303797","full_name":"ysbaddaden/panzer","owner":"ysbaddaden","description":"Multi-process, zero-downtime service monitor for Crystal","archived":false,"fork":false,"pushed_at":"2016-12-24T23:39:56.000Z","size":7,"stargazers_count":29,"open_issues_count":1,"forks_count":6,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-26T16:46:06.329Z","etag":null,"topics":["crystal"],"latest_commit_sha":null,"homepage":null,"language":"Crystal","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ysbaddaden.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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,"zenodo":null}},"created_at":"2016-12-24T23:39:27.000Z","updated_at":"2022-03-06T16:30:37.000Z","dependencies_parsed_at":"2023-06-25T22:48:12.173Z","dependency_job_id":null,"html_url":"https://github.com/ysbaddaden/panzer","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ysbaddaden/panzer","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ysbaddaden%2Fpanzer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ysbaddaden%2Fpanzer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ysbaddaden%2Fpanzer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ysbaddaden%2Fpanzer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ysbaddaden","download_url":"https://codeload.github.com/ysbaddaden/panzer/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ysbaddaden%2Fpanzer/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30287843,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-09T02:57:19.223Z","status":"ssl_error","status_checked_at":"2026-03-09T02:56:26.373Z","response_time":61,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["crystal"],"created_at":"2024-11-11T03:09:19.588Z","updated_at":"2026-03-09T08:32:38.054Z","avatar_url":"https://github.com/ysbaddaden.png","language":"Crystal","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Panzer\n\nMulti-process service monitor for Crystal, to squeeze all the juice from modern\nmulticore CPUs; also featuring zero-downtime restarts.\n\nMulti-process is achieved using a \"monitor process\" that will load the\napplication, allowing to load configuration and create servers once, then\nforking the monitor application into a specified number of processes. The\n\"monitor process\" will monitor workers, and restart them whenever one fails, so\nthe number of running workers is constant.\n\nZero-downtime is achieved using a \"main process\" whose sole job is to start a\n\"monitor process\", starting a new one in parallel when asked to (on `SIGUSR1`),\nthen killing the previous process once the new has started. It also takes care\nto restart a new \"monitor process\" if the current one ever crashes.\n\nPlease note that zero-downtime is still a work-in-progress for incoming socket\nconnections. A restart of the example provided below seems to never miss a\nconnection, but still generates some read/write errors.\n\n## Install\n\nAdd `panzer` to your shard's dependencies, then run `shards install`. This will\nbuild and install a `bin/panzer` executable into your project.\n\n```yaml\ndependencies:\n  panzer:\n    github: ysbaddaden/panzer\n```\n\n## Usage\n\nYou need a worker process.\n\nIt's a simple class that implements a `run` method —that musn't return,\notherwise your worker will terminate. This `run` method will be executed in each\nworker, forked from the monitor process, but the class initializer and any code\nloaded by your worker will be executed once.\n\nYou'll may want to delay or have to reconnect some connections in each worker\nfor resources that can't be shared between processes (e.g. database\nconnections).\n\nExample:\n\n```crystal\nrequire \"http/server\"\nrequire \"panzer/monitor\"\n\nclass MyWorker\n  include Panzer::Worker\n\n  getter port : Int32\n  private getter server : HTTP::Server\n\n  # The worker is initialized once\n  def initialize(@port)\n    @server = HTTP::Server.new(port) do |ctx|\n      ctx.response.content_type = \"text/plain\"\n      ctx.response.print \"Hello world, got #{context.request.path}!\"\n    end\n\n    # force creation of underling TCPServer\n    @server.bind\n  end\n\n  # The run method is executed for *each* worker\n  def run\n    logger.info \"listening on #{server.local_address}\"\n    server.listen\n  end\nend\n\n# Start the monitor that will manage worker processes:\nPanzer::Monitor.run(MyWorker.new(8080), count: 8)\n```\n\nYou may now build and run your application:\n\n```shell\n$ crystal build --release src/my_worker.cr -o bin/my_worker\n$ bin/panzer bin/my_worker\n```\n\nYou may restart your application by sending the `SIGUSR1` signal to the main\nprocess, which `1234` is the PID of the main process:\n\n```shell\n$ kill -USR1 1234\n```\n\nYou may tell your application to exit gracefully by sending the `SIGTERM`\nsignal, that will be propagated down to each worker:\n\n```shell\n$ kill -TERM 1234\n```\n\n## TODO\n\nmain process:\n\n  - [ ] support a YAML file (`config/panzer.yml`) to read configuration from (?)\n  - [ ] --quiet and --verbose CLI start options\n  - [ ] --timeout CLI option\n  - [ ] retry delay to restart monitor on successive crashes (--delay option)\n  - [ ] restart main process itself on SIGUSR2\n\nmonitor process:\n\n  - [ ] detect CPU number and use it as default workers count\n  - [ ] retry delay to restart workers on successive crashes\n  - [ ] print worker status on SIGTTIN\n\npanzerctl helper (?):\n\n  - [ ] requires main process to save `tmp/panzer.pid` file\n  - [ ] `--pid=/tmp/panzer.pid` option\n  - [ ] status (send SIGTTIN)\n  - [ ] reload (send SIGUSR1)\n  - [ ] restart (send SIGUSR2)\n  - [ ] shutdown (send SIGTERM)\n  - [ ] exit (send SIGINT)\n\ntests:\n\n  - [ ] integration tests that will build/run/kill/assert processes\n\n## Authors\n\n- Julien Portalier (creator, maintainer)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fysbaddaden%2Fpanzer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fysbaddaden%2Fpanzer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fysbaddaden%2Fpanzer/lists"}