Skip to content

feat: cookie name as cluster name #8

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 29, 2023
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
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,13 @@ config :libcluster,
database: "postgres",
port: 5432,
parameters: [],
# optional, defaults to node cookie
channel_name: "cluster"
],
]
]
```

Then add it to your supervision tree:

```elixir
Expand All @@ -60,6 +62,6 @@ defmodule MyApp do
end
```


## Acknowledgements
A special thank you to [@gotbones](https://twitter.com/gotbones) for creating libcluster and [@kevinbuch_](https://twitter.com/kevinbuch_) for the original inspiration for this strategy.

A special thank you to [@gotbones](https://twitter.com/gotbones) for creating libcluster and [@kevinbuch\_](https://twitter.com/kevinbuch_) for the original inspiration for this strategy.
14 changes: 12 additions & 2 deletions lib/strategy.ex
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ defmodule LibclusterPostgres.Strategy do
## Options

* `heartbeat_interval` - The interval at which to send heartbeat messages in milliseconds (optional; default: 5_000)
* `channel_name` - The name of the channel to which nodes will listen and notify (optional; default: "cluster")
* `channel_name` - The name of the channel to which nodes will listen and notify (optional; defaults to the result of `Node.get_cookie/0`)
"""
use GenServer

Expand All @@ -24,18 +24,21 @@ defmodule LibclusterPostgres.Strategy do
{:ok, %{:config => list(), :meta => map(), optional(any()) => any()},
{:continue, :connect}}
def init([state]) do
channel_name = Keyword.get(state.config, :channel_name, clean_cookie(Node.get_cookie()))

opts = [
hostname: Keyword.fetch!(state.config, :hostname),
username: Keyword.fetch!(state.config, :username),
password: Keyword.fetch!(state.config, :password),
database: Keyword.fetch!(state.config, :database),
port: Keyword.fetch!(state.config, :port),
parameters: Keyword.fetch!(state.config, :parameters),
channel_name: Keyword.fetch!(state.config, :channel_name)
channel_name: channel_name
]

config =
state.config
|> Keyword.put_new(:channel_name, channel_name)
|> Keyword.put_new(:heartbeat_interval, 5_000)
|> Keyword.delete(:url)

Expand Down Expand Up @@ -103,4 +106,11 @@ defmodule LibclusterPostgres.Strategy do
defp heartbeat(interval) when interval >= 0 do
Process.send_after(self(), :heartbeat, interval)
end

# Replaces all non alphanumeric values into underescore
defp clean_cookie(cookie) when is_atom(cookie), do: cookie |> Atom.to_string() |> clean_cookie()

defp clean_cookie(str) when is_binary(str) do
String.replace(str, ~r/\W/, "_")
end
end
7 changes: 7 additions & 0 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ defmodule LibclusterPostgres.MixProject do
deps: deps(),
package: package(),
docs: docs(),
aliases: aliases(),
source_url: "https://github.com/supabase/libcluster_postgres",
elixirc_paths: elixirc_paths(Mix.env()),
description: "Postgres strategy for libcluster"
Expand Down Expand Up @@ -49,4 +50,10 @@ defmodule LibclusterPostgres.MixProject do

defp elixirc_paths(:test), do: ["lib", "test", "test/support"]
defp elixirc_paths(_), do: ["lib"]

defp aliases() do
[
test: ["cmd epmd -daemon", "test"]
]
end
end
28 changes: 27 additions & 1 deletion test/strategy_test.exs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
defmodule LibclusterPostgres.StrategyTest do
use ExUnit.Case
use ExUnit.Case, async: false

alias Postgrex.Notifications

Expand All @@ -25,4 +25,30 @@ defmodule LibclusterPostgres.StrategyTest do

assert_receive {:notification, _, _, ^channel_name, ^node}, 1000
end

describe "connect via cookie" do
@cookie_config Keyword.put(@config, :channel_name, "my_random__123_long_cookie")
@cookie :"my-random-#123-long-cookie"
setup do
cookie = Node.get_cookie()
Node.set_cookie(Node.self(), @cookie)

on_exit(fn ->
Node.set_cookie(Node.self(), cookie)
end)
end

test "cookie default connection" do
verify_conn_notification = start_supervised!({Notifications, @cookie_config})
Notifications.listen(verify_conn_notification, @cookie_config[:channel_name])

config = Keyword.delete(@cookie_config, :channel_name)
topologies = [postgres: [strategy: LibclusterPostgres.Strategy, config: config]]
start_supervised!({Cluster.Supervisor, [topologies]})

channel_name = @cookie_config[:channel_name]
node = "#{node()}"
assert_receive {:notification, _, _, ^channel_name, ^node}, 1000
end
end
end
3 changes: 3 additions & 0 deletions test/test_helper.exs
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
# start distributed node
:net_kernel.start([:"[email protected]"])

ExUnit.start()