Skip to content
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

More compatibility #2

Merged
merged 2 commits into from
Mar 29, 2024
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
2 changes: 1 addition & 1 deletion .credo.exs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@
#
{Credo.Check.Refactor.Apply, []},
{Credo.Check.Refactor.CondStatements, []},
{Credo.Check.Refactor.CyclomaticComplexity, [max_complexity: 10]},
{Credo.Check.Refactor.CyclomaticComplexity, []},
{Credo.Check.Refactor.FilterCount, []},
{Credo.Check.Refactor.FilterFilter, []},
{Credo.Check.Refactor.FunctionArity, []},
Expand Down
25 changes: 21 additions & 4 deletions .formatter.exs
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
# Used by "mix format"
[
plugins: [Styler],
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]

defmodule LocalFormat do
@moduledoc false
def format(styler_compat) when styler_compat in [:gt, :eq] do
[
plugins: [Styler],
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]
end

def format(_) do
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]
end
end

elixir_version = System.version()
styler_compat = Version.compare(elixir_version, "1.14.0")

LocalFormat.format(styler_compat)
59 changes: 49 additions & 10 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,51 @@ permissions:

jobs:
test_linux_elixir_latest:
name: ${{ matrix.os }}, Erlang/OTP ${{ matrix.otp_version }} Elixir ${{ matrix.elixir_version }}
name: ${{ matrix.os }}, Erlang/OTP ${{ matrix.otp-version }} Elixir ${{ matrix.elixir-version }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
elixir_version: ['1']
otp_version: ['26']
include:
- os: ubuntu-20.04
elixir-version: 1.12
otp-version: 24
- os: ubuntu-20.04
elixir-version: 1.13
otp-version: 24
- os: ubuntu-20.04
elixir-version: 1.13
otp-version: 25
- os: ubuntu-20.04
elixir-version: 1.14
otp-version: 24
- os: ubuntu-20.04
elixir-version: 1.14
otp-version: 25
- os: ubuntu-22.04
elixir-version: 1.14
otp-version: 26
- os: ubuntu-20.04
elixir-version: 1.15
otp-version: 24
- os: ubuntu-20.04
elixir-version: 1.15
otp-version: 25
- os: ubuntu-22.04
elixir-version: 1.15
otp-version: 26
- os: ubuntu-20.04
elixir-version: 1.16
otp-version: 24
- os: ubuntu-20.04
elixir-version: 1.16
otp-version: 25
- os: ubuntu-20.04
elixir-version: 1.16
otp-version: 26
- os: ubuntu-22.04
elixir-version: 1.16
otp-version: 26
env:
MIX_ENV: test
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand All @@ -27,19 +64,21 @@ jobs:
- name: Set up Elixir
uses: erlef/setup-beam@v1
with:
elixir-version: ${{ matrix.elixir_version }}
otp-version: ${{ matrix.otp_version }}
elixir-version: ${{ matrix.elixir-version }}
otp-version: ${{ matrix.otp-version }}
- name: Restore dependencies cache
uses: actions/cache@v4
with:
path: deps
key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }}
restore-keys: ${{ runner.os }}-mix-
key: ${{ runner.os }}-${{ matrix.elixir-version }}-${{ matrix.otp-version}}-mix-${{ hashFiles('**/mix.lock') }}
restore-keys: ${{ runner.os }}-${{ matrix.elixir-version}}-${{ matrix.otp-version }}-mix-
- name: Install dependencies
run: mix deps.get
- name: Run mix format
run: mix format --check-formatted
- name: Run coverage export
run: mix coveralls.github
if: startsWith(matrix.elixir-version, '1.14') || startsWith(matrix.elixir-version, '1.15') || startsWith(matrix.elixir-version, '1.16')
- name: Run tests
run: mix test
- name: Run coverage export
run: mix coveralls.github
if: startsWith(matrix.elixir-version, '1.16') && startsWith(matrix.otp-version, '26')
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,6 @@ dns_srv_cluster-*.tar

# VSCode
/.vscode/

# ASDF
.tool-versions
23 changes: 18 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Elixir clustering with DNS SRV records.

---

[![CI](https://github.com/pertsevds/dns_srv_cluster/actions/workflows/ci.yml/badge.svg)](https://github.com/pertsevds/dns_srv_cluster/actions/workflows/ci.yml)
[![Coverage Status](https://coveralls.io/repos/github/pertsevds/dns_srv_cluster/badge.svg?branch=main)](https://coveralls.io/github/pertsevds/dns_srv_cluster?branch=main)

## Installation
Expand All @@ -21,10 +22,10 @@ end
Add to your DNS zone your SRV record (https://en.wikipedia.org/wiki/SRV_record):

```sh
_app._tcp.yourdomain.com. 86400 IN SRV 0 10 1234 node1.yourdomain.com.
_app._tcp.yourdomain.com. 86400 IN SRV 0 10 1234 node2.yourdomain.com.
_app._tcp.yourdomain.com. 86400 IN SRV 0 10 1234 node3.yourdomain.com.
_app._tcp.yourdomain.com. 86400 IN SRV 0 10 1234 node4.yourdomain.com.
_app._tcp.yourdomain.com. 60 IN SRV 0 10 1234 node1.yourdomain.com.
_app._tcp.yourdomain.com. 60 IN SRV 0 10 1234 node2.yourdomain.com.
_app._tcp.yourdomain.com. 60 IN SRV 0 10 1234 node3.yourdomain.com.
_app._tcp.yourdomain.com. 60 IN SRV 0 10 1234 node4.yourdomain.com.
```

Add to your config files (`config/prod.exs`, `config/dev.exs`):
Expand All @@ -49,7 +50,7 @@ either in your deployment platform or inside `rel/env.sh.eex`:
export RELEASE_COOKIE="my-app-cookie"
```

## All configuration options
## Configuration options

* `query` - your DNS SRV record, for example: "_app._tcp.yourdomain.com".
* `interval` - the millisec interval between DNS queries. Defaults to `5_000`.
Expand Down Expand Up @@ -80,4 +81,16 @@ children = [
{:ok, pid} = Supervisor.start_link(children, strategy: :one_for_one)
```

## Support Matrix

Tests automatically run against a matrix of OTP and Elixir Versions, see the [ci.yml](https://github.com/pertsevds/dns_srv_cluster/tree/main/.github/workflows/ci.yml) for details.

| OTP \ Elixir | 1.12 | 1.13 | 1.14 | 1.15 | 1.16 |
|:------------:|:----:|:----:|:----:|:----:|:----:|
| 24 | ✅ | ✅ | ✅ | ✅ | ✅ |
| 25 | N/A | ✅ | ✅ | ✅ | ✅ |
| 26 | N/A | N/A | ✅ | ✅ | ✅ |

## Documentation

Documentation can be found at <https://hexdocs.pm/dns_srv_cluster>.
9 changes: 4 additions & 5 deletions lib/dns_srv_cluster/app.ex
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,10 @@ defmodule DNSSRVCluster.App do

case query do
{:ok, query} ->
child_spec =
[
{DNSSRVCluster.Worker,
query: query, interval: interval(), connect_timeout: connect_timeout(), resolver: resolver()}
]
child_spec = [
{DNSSRVCluster.Worker,
query: query, interval: interval(), connect_timeout: connect_timeout(), resolver: resolver()}
]

opts = [strategy: :one_for_one, name: DNSSRVCluster.Supervisor]
Supervisor.start_link(child_spec, opts)
Expand Down
17 changes: 13 additions & 4 deletions lib/dns_srv_cluster/resolver.ex
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
defmodule DNSSRVCluster.Resolver do
@moduledoc false
require Logger
require Record

Record.defrecord(:hostent, Record.extract(:hostent, from_lib: "kernel/include/inet.hrl"))

# Public

Expand All @@ -20,11 +24,16 @@ defmodule DNSSRVCluster.Resolver do
def list_connected_nodes, do: Node.list(:visible)

def lookup(query, type) when is_binary(query) and type in [:srv] do
:inet_res.lookup(~c"#{query}", :in, type)
case :inet_res.getbyname(~c"#{query}", type) do
{:ok, hostent(h_addr_list: addr_list)} ->
addr_list

{:error, _} ->
Logger.warning(~s(inet_res.getbyname for query "#{query}" with type "#{type}"failed.))
[]
end
end

@spec my_node() :: atom()
def my_node do
node()
end
def my_node, do: node()
end
10 changes: 7 additions & 3 deletions lib/dns_srv_cluster/worker.ex
Original file line number Diff line number Diff line change
Expand Up @@ -96,20 +96,24 @@
schedule_next_poll(state)
end

# credo:disable-for-next-line
defp warn_on_invalid_dist do
release? = is_binary(System.get_env("RELEASE_NAME"))
%{started: started} = net_state = :net_kernel.get_state()
net_state = if function_exported?(:net_kernel, :get_state, 0), do: :net_kernel.get_state()

Check warning on line 102 in lib/dns_srv_cluster/worker.ex

View workflow job for this annotation

GitHub Actions / ubuntu-20.04, Erlang/OTP 24 Elixir 1.12

:net_kernel.get_state/0 is undefined or private

Check warning on line 102 in lib/dns_srv_cluster/worker.ex

View workflow job for this annotation

GitHub Actions / ubuntu-20.04, Erlang/OTP 24 Elixir 1.13

:net_kernel.get_state/0 is undefined or private

Check warning on line 102 in lib/dns_srv_cluster/worker.ex

View workflow job for this annotation

GitHub Actions / ubuntu-20.04, Erlang/OTP 24 Elixir 1.14

:net_kernel.get_state/0 is undefined or private

Check warning on line 102 in lib/dns_srv_cluster/worker.ex

View workflow job for this annotation

GitHub Actions / ubuntu-20.04, Erlang/OTP 24 Elixir 1.15

:net_kernel.get_state/0 is undefined or private

cond do
started == :no and release? ->
!net_state ->
:ok

net_state.started == :no and release? ->
Logger.warning("""
Node not running in distributed mode. Ensure the following exports are set in your rel/env.sh.eex file:

export RELEASE_DISTRIBUTION="${RELEASE_DISTRIBUTION:-"name"}"
export RELEASE_NODE="${RELEASE_NODE:-"<%= @release.name %>"}"
""")

started == :no or (!release? and started != :no and net_state[:name_domain] != :longnames) ->
net_state.started == :no or (!release? and net_state.started != :no and net_state[:name_domain] != :longnames) ->
Logger.warning("""
Node not running in distributed mode. When running outside of a release, you must start net_kernel manually with
longnames.
Expand Down
19 changes: 15 additions & 4 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ defmodule DNSSRVCluster.MixProject do
@maintainer "Dmitriy Pertsev"

def project do
elixir_version = System.version()
styler_compat = Version.compare(elixir_version, "1.14.0")

[
app: :dns_srv_cluster,
version: @version,
elixir: "~> 1.15",
elixir: "~> 1.12",
start_permanent: Mix.env() == :prod,
package: package(),
aliases: aliases(),
Expand All @@ -21,7 +24,7 @@ defmodule DNSSRVCluster.MixProject do
"coveralls.html": :test
],
docs: docs(),
deps: deps(),
deps: deps(styler_compat),
source_url: @scm_url,
homepage_url: @scm_url,
description: "Elixir clustering with DNS SRV records"
Expand All @@ -46,12 +49,20 @@ defmodule DNSSRVCluster.MixProject do
end

# Run "mix help deps" to learn about dependencies.
defp deps do
defp deps(styler_compat) when styler_compat in [:gt, :eq] do
[
{:credo, "~> 1.7", only: [:dev, :test], runtime: false},
{:excoveralls, "~> 0.10", only: :test, runtime: false},
{:ex_doc, "~> 0.30", only: :dev, runtime: false},
{:styler, "~> 0.11", only: [:dev, :test], runtime: false}
]
end

defp deps(_) do
[
{:credo, "~> 1.7", only: [:dev, :test], runtime: false},
{:styler, "~> 0.9", only: [:dev, :test], runtime: false}
{:excoveralls, "~> 0.10", only: :test, runtime: false},
{:ex_doc, "~> 0.30", only: :dev, runtime: false}
]
end

Expand Down
Loading