anuaralfetahe
ProcessHub - process distribution library
Hello
Published a new library - ProcessHub!
ProcessHub is a library designed to manage process distribution within the Elixir cluster. Each cluster initiates its own hub under the supervision tree, and all these hubs collectively form a cluster.
Drawing inspiration from frameworks like Horde and Swarm, one of the primary motivations behind developing this library was the necessity to replicate processes in order to enhance reliability.
This library was originally a component of another project and was tightly integrated with it until it grew and I made the decision to open source it and extract it from the codebase.
Please be caution when using this library, as it is currently in an alpha release phase.
Key Features:
Cluster Distribution: ProcessHub allows you to effortlessly distribute processes across a cluster of nodes.
Configurable Strategies: Tailor your distribution strategies to your specific needs. ProcessHub offers a range of strategies for redundancy handling, process replication, network failure mitigation, and more.
Scalability and Availability: Designed with scalability and availability in mind, ProcessHub’s operations are predominantly asynchronous and non-blocking. It’s eventually consistent.
Decentralized Architecture
React to events : ships with a set of events that can be hooked into and trigger code.
Theres actually much more. Please read the documentation.
Link to the documentation: Hex
Github: Repo
Thanks ![]()
First Post!
anuaralfetahe
New version released.
v0.1.1-alpha - 2023-10-07
Elixir 1.13-1.15 support added.
Includes minor bugfixes, test fixes and documentation updates.
Added
- Added GitHub Actions for automated testing.
- Made sure that
ProcessHubis compatible with Elixir 1.13-1.15. - Added example usage section to the documentation.
Changed
- Updated
ProcessHubdocumentation by adding a list of all available strategies. - Removed unnecessary file .tool-version generated by asdf.
Fixed
- README.md table of contents links fixed.
- Fixed
ProcessHubawait/1 function example code formatting. - Fixed tests for elixir 1.15 & OTP 26
- Fixed test case which was failing in some cases due to async call being executed before.
The library is still in the alpha phase, feedback and suggestions are welcome. If you have any issues, please open an issue or a pull request on Github.
Most Liked
lawik
Just FYI, ProcessHub is used in NervesHub which means it is used for some reasonably large deployments. Several 100K devices connected to double digit nodes in some installs.
Don’t think we’ve had any issues. I haven’t worked on that part so much but seems like a clean solution.
We use it for a fairly simple thing. Important but not intense. Make sure we run one orchestrator process for distribution of firmware updates per deployment group im the cluster. The orchestrator keeps tabs on the number of concurrent updates and stuff. Tells other processes what to do.
Though that might be of interest ![]()
slouchpie
I started exploring this library a few hours ago and it is extremely good. I have used horde in the past and pogo more recently. Both of those libs are great but process_hub is truly a joy to use.
There is a lot to love and I have not even started using the hot-swapping and hooks stuff. Reading the list of hook events blew my mind. My imagination was piqued.
I love the simplicity of the hub_id atom. This plays well with Fly because the fly region can be used to build the hub_id, for simple per-region clustering.
I also love the way you use local ETS tables for fast lookup. Perfect use-case for ets.
I am still doing a refactor on a feature branch to see if my own hacky :pogo-based attempts at distributed process management can be replaced with :process_hub. So far I refactored a cache for oauth “state” and a per-kitchen “global singleton” order number generator process. I have way less LOC already and it is far simpler to read and understand.
I am in awe. Congratulations.
anuaralfetahe
New version release 0.5.0-beta ![]()
This one includes many performance optimisations, bugfixes, new features, some breaking changes and large scale code refactoring.
You can look at the changelog here: Release v0.5.0-beta · alfetahe/process-hub · GitHub
I have a lot of ideas and features I’d like to add to this library, but I also want to prioritize stability. In this release, I’ve marked several new features as experimental. This means they may undergo breaking changes or be dropped entirely in future updates.
Here are some performance benchmarks comparing this version and the previous one starting and stopping 10k processes on 10 nodes (running on the same machine).
I used the same laptop to run the tests.
The new version is up to ~10x faster then the previous one and uses ~2x less memory.
This is ~250ms to start and stop 10k processes on 10 nodes.
Host:
Operating System: Linux
CPU Information: 13th Gen Intel(R) Core™ i7-13700H
Number of Available Cores: 20
Available memory: 62.43 GB
Elixir 1.19.3
Erlang 28.1.1
JIT enabled: true
v0.5.0-beta
Name ips average deviation median 99th %
start_&_stop_processes 4.28 233.64 ms ±129.04% 57.73 ms 827.01 ms
Memory usage statistics:
Name average deviation median 99th %
start_&_stop_processes 449.77 KB ±77.20% 380.79 KB 1030.14 KB
v0.4.1-beta
Name ips average deviation median 99th %
start_&_stop_processes 0.48 2.07 s ±0.63% 2.08 s 2.08 s
Memory usage statistics:
Name Memory usage
start_&_stop_processes 879.66 KB
Last Post!
anuaralfetahe
New version released 0.6.0 yes, the beta tag is officially gone! ![]()
The library has been in use for some time now and has been stable. While I still have many ideas for new features, the core functionality and public API will likely stay as they are unless there is a clear need to change them.
In the future, I will keep releasing new features, and some will be marked as experimental just as I’ve done so far. If these features stand the test of time and prove useful, they will become part of the stable core.
Here’s the changelog:
## v0.6.0 - 2026-07-11
This release is aimed at making the system more resilient: a pluggable registry backend (ETS stays the default, with on-disk and hybrid options today and room for further storage integrations), safe migration — processes can defer their own migration and a node can be drained before shutdown — and experimental recovery mechanisms. It also includes a few bug fixes.
### Added
- Pluggable registry storage backend: new `:registry_backend` field on `%ProcessHub{}` (default `:ets`). Accepts `:ets`, `{:dets, opts}`, `{:durable_ets, opts}`, or `{Module, opts}` for a custom backend implementing `ProcessHub.Service.Storage.Behaviour`.
- `:ets` — default in-memory backend (unchanged behaviour).
- `{:dets, opts}` — on-disk persistence: sync-after-write durability, `repair: true` on open, and corruption rotation.
- `{:durable_ets, opts}` — hybrid: in-memory reads with synchronous DETS mirroring for restart survival. Shares the DETS on-disk format, so a hub can switch between `:dets` and `:durable_ets` against the same `:path` and keep its rows.
- Opt-in migration consent: `:consent_settings` on `HotSwap`/`ColdSwap` (default `nil` — disabled, no overhead). A process that does `use ProcessHub.Strategy.Migration.MigrationConsent` is asked before it is migrated; `:defer` (or no reply within `:consent_timeout`) parks it in a deferred list, retried every `:retry_interval` and force-migrated after `:max_defer_time`. `ProcessHub.Service.Migration.migration_ready/2` signals readiness early. Primary instances only; processes started through wrapper modules are not detected.
- `ProcessHub.Service.Migration.drain/2` — blocking graceful node drain before shutdown. Removes the node from the distribution cluster-wide, migrates all local children away through the consent gate, and force-migrates whatever is still deferred at the `:timeout` deadline (default `60_000` ms). Returns `{:ok, %{migrated: n, forced: m}}`, or an error without touching children when no other node exists or the hub is partitioned/locked. Not reversible — restart the hub to rejoin.
- New hooks: `migration_deferred` (child ids parked) and `drain_completed` (drain summary).
- New guide `guides/Persistence.md` covering the persistence backends and the recovery lifecycle / operator runbook.
- **Experimental:** opt-in, marker-gated boot recovery via the single `:auto_recovery` field on `%ProcessHub{}` (default `false`). Accepts `false`, `true`, or a keyword list of `:marker_path` (operator override for the marker file location) and `:recovery_timeout_ms` (safety ceiling on the `:recovering` state, default `30_000`). A successful boot writes the marker file; on next boot the node skips replay if the marker is present, or rebuilds from disk if it is absent (state is `:recovering` → `:normal`). Disk replay restores only child specs — stale pids and metadata are dropped (fixes a restarted node pushing stale registry data into a healthy cluster).
- API on `ProcessHub.Service.Recovery`: `recovery_state/1`, `await_normal/2`, `prepare_recovery/1`, and `prepare_recovery_cluster/1` (all safe to call on non-opted-in hubs).
- New hooks: `recovery_state_changed`, `pre_recovery_replay` (**synchronous** — the coordinator awaits each handler), and `post_recovery_replay`.
- **Experimental:** `:nodeup_reconcile_interval` field on `%ProcessHub{}` (default `3000` ms; `0` disables) — fail-safe that merges a peer if the `pg` cluster-join notification is missed on a reconnection, closing a split-brain gap.
### Fixed
- Fast-restart stale bindings are now reaped on every backend (including default `:ets`). A node that restarts within `:net_ticktime` (no `:nodedown`) left peers pointing at its dead pids, since the rejoin sync only appends. Each node now broadcasts a per-boot token; peers purge a node's bindings only when its token changes (distinguishing a restart from a network flap). This replaces the previous purge signal that was gated behind `:auto_recovery`.
- Registry sync (`Synchronizer.append_data/2`) no longer overwrites a known child's local child-spec and metadata with a peer's copy on a pid change — it only updates the pid map. A node replaying stale durable state could otherwise clobber a peer's current spec, leaving a degraded process after redistribution.
- `mix docs` now builds with zero warnings: dropped the auto-generated `:supervisor` delegate docs, corrected doc references to the `init_opts`/`stop_opts` types and the `ProcessHub.Service.Storage.Behaviour` module, and removed a reference to a non-existent DETS compaction function.
- Janitor TTL cleanup no longer wipes a re-registered process. `purge_pending_registry/1` scanned the registry with a dirty `:ets.match` read and then deleted unconditionally; an incoming registration that re-populated a TTL tombstone between the scan and the delete could be erased. Cleanup now goes through `ProcessRegistry.delete_if_expired/2`, which re-validates expiry inside the registry process and skips the delete if the entry was re-populated or re-leased.
- Registry no longer keeps dead pids after quorum recovery. On quorum failure the distributed supervisor is terminated and its children are killed, but their registry entries are retained as the restart manifest. On recovery (`State.toggle_quorum_success/1`) the supervisor restarts the children with fresh pids that were only tracked internally, leaving the registry pointing at the dead pids — which were then propagated to the rest of the cluster on the next sync. Recovery now refreshes the local node's pids in the registry to the actually-running ones.
Popular in Announcing
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex









