-
Notifications
You must be signed in to change notification settings - Fork 161
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor persistent term usage to behaviour (#344)
- Loading branch information
Showing
6 changed files
with
250 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
defmodule Broadway.ConfigStorage do | ||
@moduledoc false | ||
alias Broadway.ConfigStorage.{Ets, PersistentTerm} | ||
|
||
@doc """ | ||
Optional setup for the configuration storage | ||
""" | ||
@callback setup() :: :ok | ||
|
||
@doc """ | ||
Lists all broadway names in the config storage | ||
""" | ||
@callback list() :: [term()] | ||
|
||
@doc """ | ||
Puts the given key value pair in the underlying storage. | ||
""" | ||
@callback put(server :: term(), value :: %Broadway.Topology{}) :: term() | ||
|
||
@doc """ | ||
Retrieves a configuration from the underlying storage | ||
""" | ||
@callback get(server :: term()) :: term() | ||
|
||
@doc """ | ||
Deletes a configuration from the underlying storage | ||
""" | ||
@callback delete(server :: term()) :: boolean() | ||
|
||
@optional_callbacks setup: 0 | ||
|
||
@doc """ | ||
Retrieves the configured module based on the `:config_storage` key. | ||
""" | ||
@spec get_module() :: module() | ||
def get_module() do | ||
Application.get_env(Broadway, :config_storage, :persistent_term) | ||
|> case do | ||
:ets -> Ets | ||
:persistent_term -> PersistentTerm | ||
mod -> mod | ||
end | ||
end | ||
|
||
@doc """ | ||
Retrieves any options set on the `:config_storage` key. | ||
""" | ||
@spec get_options() :: keyword() | ||
def get_options() do | ||
Application.get_env(Broadway, :config_storage_opts) || [] | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
defmodule Broadway.ConfigStorage.Ets do | ||
@moduledoc false | ||
alias Broadway.ConfigStorage | ||
@behaviour ConfigStorage | ||
|
||
@default_table :broadway_configs | ||
|
||
def default_table(), do: @default_table | ||
|
||
@impl ConfigStorage | ||
def setup do | ||
if :undefined == :ets.whereis(table()) do | ||
:ets.new(table(), [:named_table, :public, :set, {:read_concurrency, true}]) | ||
end | ||
|
||
:ok | ||
end | ||
|
||
@impl ConfigStorage | ||
def list do | ||
:ets.select(table(), [{{:"$1", :_}, [], [:"$1"]}]) | ||
end | ||
|
||
@impl ConfigStorage | ||
def get(server) do | ||
case :ets.match(table(), {server, :"$1"}) do | ||
[[topology]] -> topology | ||
_ -> nil | ||
end | ||
end | ||
|
||
@impl ConfigStorage | ||
def put(server, topology) do | ||
:ets.insert(table(), {server, topology}) | ||
end | ||
|
||
@impl ConfigStorage | ||
def delete(server) do | ||
:ets.delete(table(), server) | ||
end | ||
|
||
defp table() do | ||
opts = ConfigStorage.get_options() | ||
Keyword.get(opts, :table_name, @default_table) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
defmodule Broadway.ConfigStorage.PersistentTerm do | ||
@moduledoc false | ||
@behaviour Broadway.ConfigStorage | ||
|
||
@impl Broadway.ConfigStorage | ||
def setup do | ||
unless Code.ensure_loaded?(:persistent_term) do | ||
require Logger | ||
Logger.error("Broadway requires Erlang/OTP 21.3+") | ||
raise "Broadway requires Erlang/OTP 21.3+" | ||
end | ||
|
||
:ok | ||
end | ||
|
||
@impl Broadway.ConfigStorage | ||
def list do | ||
for {{Broadway, name}, %Broadway.Topology{}} <- :persistent_term.get() do | ||
name | ||
end | ||
end | ||
|
||
@impl Broadway.ConfigStorage | ||
def get(server) do | ||
:persistent_term.get({Broadway, server}, nil) | ||
end | ||
|
||
@impl Broadway.ConfigStorage | ||
def put(server, topology) do | ||
:persistent_term.put({Broadway, server}, topology) | ||
end | ||
|
||
@impl Broadway.ConfigStorage | ||
def delete(_server) do | ||
# We don't delete from persistent term on purpose. Since the process is | ||
# named, we can assume it does not start dynamically, so it will either | ||
# restart or the amount of memory it uses is negligibla to justify the | ||
# process purging done by persistent_term. If the repo is restarted and | ||
# stores the same metadata, then no purging happens either. | ||
# :persistent_term.erase({Broadway, server}) | ||
true | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
defmodule Broadway.ConfigStorageTest do | ||
use ExUnit.Case, async: false | ||
alias Broadway.ConfigStorage.Ets | ||
|
||
setup do | ||
prev = Application.get_env(Broadway, :config_storage) | ||
prev_opts = Application.get_env(Broadway, :config_storage_opts) | ||
|
||
on_exit(fn -> | ||
Application.put_env(Broadway, :config_storage, prev) | ||
Application.put_env(Broadway, :config_storage_opts, prev_opts) | ||
end) | ||
end | ||
|
||
test "ets default options" do | ||
Application.put_env(Broadway, :config_storage, :ets) | ||
Ets.setup() | ||
assert [] = Ets.list() | ||
assert Ets.put("some name", %Broadway.Topology{}) | ||
assert ["some name"] = Ets.list() | ||
assert %Broadway.Topology{} = Ets.get("some name") | ||
assert :ets.info(Ets.default_table(), :size) == 1 | ||
Ets.delete("some name") | ||
assert :ets.info(Ets.default_table(), :size) == 0 | ||
end | ||
|
||
test "ets custom name" do | ||
Application.put_env(Broadway, :config_storage, :ets) | ||
Application.put_env(Broadway, :config_storage_opts, table_name: :my_table) | ||
Ets.setup() | ||
assert :ets.info(:my_table, :size) == 0 | ||
assert [] = Ets.list() | ||
assert Ets.put("some name", %Broadway.Topology{}) | ||
assert ["some name"] = Ets.list() | ||
assert %Broadway.Topology{} = Ets.get("some name") | ||
assert :ets.info(:my_table, :size) == 1 | ||
Ets.delete("some name") | ||
assert :ets.info(:my_table, :size) == 0 | ||
end | ||
end |