{"id":15010149,"url":"https://github.com/arjan/sworm","last_synced_at":"2026-02-26T09:40:37.614Z","repository":{"id":57555295,"uuid":"186692595","full_name":"arjan/sworm","owner":"arjan","description":"A user-friendly distributed process registry and process supervisor","archived":false,"fork":false,"pushed_at":"2023-03-22T11:43:28.000Z","size":120,"stargazers_count":35,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-09-28T03:19:40.973Z","etag":null,"topics":["crdt","distributed-systems","elixir"],"latest_commit_sha":null,"homepage":"","language":"Elixir","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/arjan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2019-05-14T20:08:10.000Z","updated_at":"2024-06-05T21:46:49.000Z","dependencies_parsed_at":"2024-09-24T19:31:19.656Z","dependency_job_id":"b01ed2d8-8916-4c3b-9780-99c38521a8b6","html_url":"https://github.com/arjan/sworm","commit_stats":{"total_commits":94,"total_committers":2,"mean_commits":47.0,"dds":0.08510638297872342,"last_synced_commit":"4e4661a9af6c998777e2ce431c9046519e8a3647"},"previous_names":[],"tags_count":27,"template":false,"template_full_name":null,"purl":"pkg:github/arjan/sworm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arjan%2Fsworm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arjan%2Fsworm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arjan%2Fsworm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arjan%2Fsworm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/arjan","download_url":"https://codeload.github.com/arjan/sworm/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arjan%2Fsworm/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29855493,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-26T08:51:08.701Z","status":"ssl_error","status_checked_at":"2026-02-26T08:50:19.607Z","response_time":89,"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":["crdt","distributed-systems","elixir"],"created_at":"2024-09-24T19:30:50.903Z","updated_at":"2026-02-26T09:40:37.593Z","avatar_url":"https://github.com/arjan.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Sworm\n\n[![Build status](https://github.com/arjan/sworm/actions/workflows/test.yml/badge.svg)](https://github.com/arjan/sworm/actions/workflows/test.yml)\n[![Hex pm](https://img.shields.io/hexpm/v/sworm.svg?style=flat)](https://hex.pm/packages/sworm)\n[![Hex Docs](https://img.shields.io/badge/hex-docs-lightgreen.svg)](https://hexdocs.pm/sworm/)\n[![Total Download](https://img.shields.io/hexpm/dt/sworm.svg)](https://hex.pm/packages/sworm)\n[![License](https://img.shields.io/hexpm/l/sworm.svg)](https://github.com/arjan/sworm/blob/master/LICENSE)\n[![Last Updated](https://img.shields.io/github/last-commit/arjan/sworm.svg)](https://github.com/arjan/sworm/commits/master)\n\nA combination of a global, distributed process registry and\nsupervisor, rolled into one, friendly API.\n\nThis library aims to be a drop-in replacement for\n[Swarm](https://github.com/bitwalker/swarm), but it is built on top of\n[Horde](https://github.com/derekkraan/horde).\n\n## Usage\n\nSworms can be defined using a macro and then added to your supervision\ntree. To replicate Swarm, create the following module:\n\n```elixir\ndefmodule Swarm do\n  use Sworm\nend\n```\n\nYou are not entirely done yet! Unlike the original Swarm, which has a\n\"singleton\" process tree, you will need to add each `Sworm` to your\nown application's supervision tree:\n\n```elixir\n    children = [\n      Swarm,\n      ...\n    ]\n```\n\nNow you can call `Swarm.registered()`, `Swarm.register_name` etc like you're used to.\n\n## Architecture\n\nSworm combines Horde's DynamicSupervisor and Registry modules to\nreproduce the Swarm library.\n\nTo be able to register an aribtrary `{m, f, a}` specification with\nSworm, it spawns a _delegate process_ and uses this process as the\nprimary process for name registration and supervision. This delegate\nprocess then spawns and links the actual process as specified in the\nMFA.\n\nThis way, any MFA can be used with Sworm like it can with Swarm, and\ndoes not need to be aware of it, because the delegate process handles\nname registration, process shutdown on name conflicts, and process handoff.\n\n## Node affinity / node deny-/allowlisting\n\nContrarily to Swarm, Sworm does not have a deny- or allowlisting\nmechanism. By design, each Sworm in the cluster only distributes\nprocesses among those nodes that explicitly have that particular sworm\nstarted in its supervision tree.\n\nSworm maintains a cluster-global directory CRDT of registered Sworms,\nkeeping track of on which node which type(s) of Sworm run.\n\nThis ensures that processes are only started through Sworm on nodes\nthat the sworm itself is also running on, instead of assuming that the\ncluster is homogenous and processes can run on each node, like Swarm\ndoes.\n\nFor an even more finegrained control over process placement, you can pass in a\ncustom [`:distribution_strategy`][dist] option on compile time, like this:\n\n```elixir\ndefmodule MyTemporaryProcesses do\n  use Sworm, distribution_strategy: Horde.UniformQuorumDistribution\nend\n```\n\nThe default distribution strategy is [Horde.UniformDistribution][dist_horde].\n\n[dist]: https://hexdocs.pm/horde/Horde.DistributionStrategy.html#t:t/0\n[dist_horde]: https://hexdocs.pm/horde/Horde.UniformDistribution.html\n\n## Child restart strategy\n\nBy default, the restart strategy in the [child\nspecification][childspec] of the supervision tree is set to\n`:transient`. To change this, declare the `restart:` option in your\nSworm module like this:\n\n```elixir\ndefmodule MyTemporaryProcesses do\n  use Sworm, restart: :temporary\nend\n```\n\n[childspec]: https://hexdocs.pm/elixir/Supervisor.html#module-child-specification\n\n## CRDT options\n\nTo override Horde's [`:delta_crdt_options`][crdt], pass them in the `use` statement:\n\n```elixir\ndefmodule MyTemporaryProcesses do\n  use Sworm, delta_crdt_options: [sync_interval: 100]\nend\n```\n\nThese CRDT options are used for both the internal Registry and the DynamicSupervisor CRDTs.\n\n[crdt]: https://hexdocs.pm/delta_crdt/0.6.4/DeltaCrdt.html#t:crdt_option/0\n\n## Process state handoff\n\nEach individual Sworm can be configured to perform state a handoff to\ntransition the state of the process.\n\nThe case here is that when a node shuts down, Sworm will move the\nprocesses running on that node onto one of the other nodes of the\ncluster. By default, these processes are started with a clean sheet,\ne.g., the state of the process is lost. But when the Sworm is\nconfigured to perform process handoffs, the processes in the sworm are\ngiven some time to hand off their state into the cluster, so that the\nstate can be restored right after the process is started again on\nanother node.\n\n\u003e Process handoff in Sworm works differently from the Swarm library.\n\nProcess handoff must be explicitly enabled per sworm:\n\n```elixir\ndefmodule MyProcesses do\n  use Sworm, handoff: true\nend\n```\n\nOr, in `config.exs`:\n\n```elixir\nconfig :sworm, MyProcesses, handoff: true\n```\n\nWhen a handoff occurs, the process that is about to exit, receives the\nfollowing message:\n\n    {MyProcesses, :begin_handoff, delegate, ref}\n\nIf it wants to pass on its internal state it needs to send the\ndelegate a corresponding ack:\n\n    send(delegate, {ref, :handoff_state, some_state})\n\nNow, on the other node, the new process will be started in the normal\nway, however, right after it is started it will receive the\n`:end_handoff` signal:\n\n     {MyProcesses, :end_handoff, some_state}\n\nIt can then restore its state to the state that was sent by its\npredecessor.\n\nThe most basic implementation in a genserver process of this flow is this:\n\n```elixir\ndef handle_info({MyProcesses, :begin_handoff, delegate, ref}, state) do\n  send(delegate, {ref, :handoff_state, state})\n  {:noreply, state}\nend\n\ndef handle_info({MyProcesses, :end_handoff, state}, _state) do\n  {:noreply, state}\nend\n```\n\n## Installation\n\nIf [available in Hex](https://hex.pm/docs/publish), the package can be installed\nby adding `sworm` to your list of dependencies in `mix.exs`:\n\n```elixir\ndef deps do\n  [\n    {:sworm, \"~\u003e 0.1\"}\n  ]\nend\n```\n\nDocumentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)\nand published on [HexDocs](https://hexdocs.pm). Once published, the docs can\nbe found at [https://hexdocs.pm/sworm](https://hexdocs.pm/sworm).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farjan%2Fsworm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Farjan%2Fsworm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farjan%2Fsworm/lists"}