Skip to content

Add Pluggable Transports and support for Partisan#289

Open
sahilpohare wants to merge 9 commits intoelixir-horde:masterfrom
sahilpohare:master
Open

Add Pluggable Transports and support for Partisan#289
sahilpohare wants to merge 9 commits intoelixir-horde:masterfrom
sahilpohare:master

Conversation

@sahilpohare
Copy link
Copy Markdown

What this solves

Horde assumes Erlang distribution throughout — Node.list() for peer discovery, :erpc for remote
calls, and a single hardcoded Horde.NodeListener for membership. This makes Horde incompatible with
alternative transports like Partisan, which replaces Erlang distribution entirely with its own mesh
networking layer.

What it introduces

Horde.NodeListenerBehaviour

A use-based behaviour for building custom node listeners. The use macro injects a full GenServer
implementation with sensible defaults — Erlang distribution monitoring, handle_nodeup/handle_nodedown,
and set_members. The only required callback is make_members/1. All injected functions are
defoverridable.

Horde.Registry and Horde.DynamicSupervisor now accept {:auto, ListenerModule} as the :members
option to start a custom listener instead of the default Horde.NodeListener.

Horde.ClusterTransport behaviour

Abstracts the primitives Horde needs from the underlying cluster transport:

Callback Purpose
members/0 Returns connected peer nodes
process_alive?/1 Checks whether a remote pid is alive
call/5 Invokes a function on a remote node

Two implementations ship out of the box:

Module Backend
Horde.ClusterTransport.Erlang Standard Erlang distribution (default)
Horde.ClusterTransport.Partisan Partisan — :partisan_peer_service + :partisan_rpc

The :transport option on Horde.Registry selects the implementation. The chosen module is stored in
registry ETS metadata at startup and read on every lookup/2 — one local ETS read, no GenServer call on
the hot path.

Horde.NodeListener.Partisan

A ready-made Partisan node listener built on Horde.NodeListenerBehaviour. Uses
:partisan.monitor_nodes/1 for monitoring and :partisan_peer_service for membership.

{Horde.Registry,
  name: MyRegistry,
  keys: :unique,
  members: {:auto, Horde.NodeListener.Partisan},
  transport: Horde.ClusterTransport.Partisan}

Conditional compilation

Horde.ClusterTransport.Partisan and Horde.NodeListener.Partisan are wrapped in
Code.ensure_loaded?(:partisan_peer_service) guards — only compiled when Partisan is present. No optional
dep entry in mix.exs, no compile-time warnings in Partisan-free builds.

Methodology

  • No breaking changes — all defaults preserve existing behaviour. :transport defaults to
    Horde.ClusterTransport.Erlang, {:auto, ListenerModule} is additive alongside the existing :auto.
  • Hot path stays fast — transport is resolved once at init and stored in ETS metadata, never changes
    at runtime.
  • Transport is stateless — just a module, no process or config storage beyond the single ETS write at
    startup.
  • Existing tests pass — 104 tests pass. 3 pre-existing failures in
    ClusterTest/NetworkPartitionTest are unrelated flaky distributed tests.

Allow passing {:auto, ListenerModule} as the node manager option in
Horde.DynamicSupervisor and Horde.Registry (handled by
maybe_add_node_manager
and members). Add Horde.NodeListenerBehaviour to provide a behaviour and
default GenServer implementation for custom node listeners. Update
mix.exs
source_url to the new repository.
Introduce Horde.ClusterTransport behaviour plus Erlang and Partisan
implementations. Add a :transport option to Horde.Registry (defaulting
to
Horde.ClusterTransport.Erlang) and store the transport module in
registry
metadata. Registry now delegates process liveness and remote calls to
the
configured transport. Also adjust NodeListenerBehaviour @impl to use
GenServer and mark node callbacks optional.
Wrap Partisan modules in a Code.ensure_loaded? check and add
rescue/error handling for :partisan_peer_service and :partisan_rpc calls
Comment thread mix.exs Outdated
@sahilpohare sahilpohare requested a review from sleipnir April 6, 2026 15:41
@sleipnir
Copy link
Copy Markdown
Collaborator

sleipnir commented Apr 6, 2026

Hi @sahilpohare, thanks for the PR, I'll review it soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants