Skip to content

Commit

Permalink
More compatibility (#2)
Browse files Browse the repository at this point in the history
* Elixir 1.12+ compatibility
OTP 24 compatibility
:inet_res.getbyname instead of :inet_res.lookup in resolver
  • Loading branch information
pertsevds authored Mar 29, 2024
1 parent 97fd665 commit cef2ba1
Show file tree
Hide file tree
Showing 9 changed files with 131 additions and 36 deletions.
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 @@ defmodule DNSSRVCluster.Worker do
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

0 comments on commit cef2ba1

Please sign in to comment.