Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Fixed

- Horde compile-time detection now checks `Horde.Registry` instead of `Horde` — horde 0.10 has no root `Horde` module, so `Code.ensure_loaded?(Horde)` always returned `false`, preventing the Horde backend from being compiled even when the dependency was installed

## [0.3.1] - 2026-02-26

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion lib/durable_object/cluster.ex
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ defmodule DurableObject.Cluster do
Returns the backend module for the current mode.
"""
@spec impl() :: module()
if Code.ensure_loaded?(Horde) do
if Code.ensure_loaded?(Horde.Registry) do
def impl do
case mode() do
:local -> DurableObject.Cluster.Local
Expand Down
2 changes: 1 addition & 1 deletion lib/durable_object/cluster/horde.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
if Code.ensure_loaded?(Horde) do
if Code.ensure_loaded?(Horde.Registry) do
defmodule DurableObject.Cluster.Horde do
@moduledoc """
Horde-mode cluster backend using Horde.Registry and Horde.DynamicSupervisor.
Expand Down
2 changes: 1 addition & 1 deletion lib/durable_object/singleton.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
if Code.ensure_loaded?(Horde) do
if Code.ensure_loaded?(Horde.Registry) do
defmodule DurableObject.Singleton do
@moduledoc """
Cluster singleton utility for ensuring only one instance of a process
Expand Down
75 changes: 37 additions & 38 deletions test/durable_object/cluster_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -70,39 +70,17 @@ defmodule DurableObject.ClusterTest do
end
end

if Code.ensure_loaded?(Horde) do
test "returns Horde for horde mode" do
original = Application.get_env(:durable_object, :registry_mode)

try do
Application.put_env(:durable_object, :registry_mode, :horde)
assert Cluster.impl() == DurableObject.Cluster.Horde
after
if original do
Application.put_env(:durable_object, :registry_mode, original)
else
Application.delete_env(:durable_object, :registry_mode)
end
end
end
end

test "raises helpful error for horde mode without Horde installed" do
unless Code.ensure_loaded?(Horde) do
original = Application.get_env(:durable_object, :registry_mode)

try do
Application.put_env(:durable_object, :registry_mode, :horde)
test "returns Horde for horde mode" do
original = Application.get_env(:durable_object, :registry_mode)

assert_raise RuntimeError, ~r/Horde mode requires the :horde dependency/, fn ->
Cluster.impl()
end
after
if original do
Application.put_env(:durable_object, :registry_mode, original)
else
Application.delete_env(:durable_object, :registry_mode)
end
try do
Application.put_env(:durable_object, :registry_mode, :horde)
assert Cluster.impl() == DurableObject.Cluster.Horde
after
if original do
Application.put_env(:durable_object, :registry_mode, original)
else
Application.delete_env(:durable_object, :registry_mode)
end
end
end
Expand Down Expand Up @@ -147,15 +125,36 @@ defmodule DurableObject.ClusterTest do
end
end

if Code.ensure_loaded?(Horde) do
describe "Horde backend" do
test "generates correct via_tuple format" do
via = DurableObject.Cluster.Horde.via_tuple(MyModule, "object-123")
describe "Horde backend" do
test "module is defined when horde dependency is available" do
assert Code.ensure_loaded?(Horde.Registry),
"Horde.Registry should be available (horde is in deps)"

assert {:via, Horde.Registry, {DurableObject.HordeRegistry, {MyModule, "object-123"}}} =
via
assert {:module, DurableObject.Cluster.Horde} =
Code.ensure_loaded(DurableObject.Cluster.Horde)
end

test "impl/0 returns Horde backend in horde mode" do
original = Application.get_env(:durable_object, :registry_mode)

try do
Application.put_env(:durable_object, :registry_mode, :horde)
assert Cluster.impl() == DurableObject.Cluster.Horde
after
if original do
Application.put_env(:durable_object, :registry_mode, original)
else
Application.delete_env(:durable_object, :registry_mode)
end
end
end

test "generates correct via_tuple format" do
via = DurableObject.Cluster.Horde.via_tuple(MyModule, "object-123")

assert {:via, Horde.Registry, {DurableObject.HordeRegistry, {MyModule, "object-123"}}} =
via
end
end

describe "integration with ObjectSupervisor" do
Expand Down