From acb46e19fb068ae5337b386f7832135952dedda2 Mon Sep 17 00:00:00 2001 From: Garry Hill Date: Tue, 17 Dec 2024 13:44:43 +0000 Subject: [PATCH] sync-service: Simplify configuration of the electric app (#2173) Refactor app config to make most values optional. Except for connection_opts, all the config settings have defaults. When embedding electric inside another elixir app, our runtime.exs won't be sourced so the developer would be forced to unnecessarily set all these configuration values. Moves the default values from runtime.exs to the point of usage so we don't have defaults in two places. --- packages/sync-service/README.md | 47 ++++++- packages/sync-service/config/runtime.exs | 49 +++---- packages/sync-service/lib/electric.ex | 125 +++++++++++++++++- .../sync-service/lib/electric/application.ex | 57 ++++---- .../electric/{config_parser.ex => config.ex} | 112 +++++++++++++++- .../lib/electric/stack_supervisor.ex | 10 +- .../sync-service/lib/electric/telemetry.ex | 9 +- .../electric/telemetry/call_home_reporter.ex | 2 +- .../test/electric/config_parser_test.exs | 5 - .../test/electric/config_test.exs | 5 + 10 files changed, 342 insertions(+), 79 deletions(-) rename packages/sync-service/lib/electric/{config_parser.ex => config.ex} (73%) delete mode 100644 packages/sync-service/test/electric/config_parser_test.exs create mode 100644 packages/sync-service/test/electric/config_test.exs diff --git a/packages/sync-service/README.md b/packages/sync-service/README.md index 4ea7c3a0ea..3b54dc0c88 100644 --- a/packages/sync-service/README.md +++ b/packages/sync-service/README.md @@ -15,7 +15,7 @@ Electric Sync is powered by an Elixir-based application that connects to your Po For a quick setup and examples, refer to the [Quickstart guide](https://electric-sql.com/docs/quickstart). -## Running +## Running as a Standalone HTTP Endpoint Run Postgres: @@ -36,3 +36,48 @@ Run the Elixir app: mix deps.get iex -S mix ``` + +## Embedding into another Elixir Application + +Include `:electric` into your dependencies: + + # mix.exs + defp deps do + [ + {:electric, ">= 1.0.0-beta-1"} + ] + end + +Add the Postgres db connection configuration to your application's config. +Electric accepts the same configuration format as +[Ecto](https://hexdocs.pm/ecto/Ecto.html) (and +[Postgrex](https://hexdocs.pm/postgrex/Postgrex.html#start_link/1)) so you can +reuse that configuration if you want: + + # config/*.exs + database_config = [ + database: "ecto_simple", + username: "postgres", + password: "postgres", + hostname: "localhost" + ] + config :my_app, Repo, database_config + + config :electric, + connection_opts: Electric.Utils.obfuscate_password(database_config) + +Or if you're getting your db connection from an environment variable, then you +can use +[`Electric.Config.parse_postgresql_uri!/1`](https://hexdocs.pm/electric/Electric.Config.html#parse_postgresql_uri!/1): + + # config/*.exs + {:ok, database_config} = Electric.Config.parse_postgresql_uri(System.fetch_env!("DATABASE_URL")) + + config :electric, + connection_opts: Electric.Utils.obfuscate_password(database_config) + +The Electric app will startup along with the rest of your Elixir app. + +Beyond the required database connection configuration there are a lot of other +optional configuration parameters. See the [`Electric` docs for more +information](https://hexdocs.pm/electric/Electric.html). diff --git a/packages/sync-service/config/runtime.exs b/packages/sync-service/config/runtime.exs index 7f3175f92a..5ad3145eae 100644 --- a/packages/sync-service/config/runtime.exs +++ b/packages/sync-service/config/runtime.exs @@ -1,15 +1,13 @@ import Config import Dotenvy -alias Electric.ConfigParser - config :elixir, :time_zone_database, Tz.TimeZoneDatabase if config_env() in [:dev, :test] do source!([".env.#{config_env()}", ".env.#{config_env()}.local", System.get_env()]) end -config :logger, level: env!("ELECTRIC_LOG_LEVEL", &ConfigParser.parse_log_level!/1, :info) +config :logger, level: env!("ELECTRIC_LOG_LEVEL", &Electric.Config.parse_log_level!/1, :info) config :logger, :default_formatter, # Doubled line breaks serve as long message boundaries @@ -106,7 +104,7 @@ config :opentelemetry, local_parent_not_sampled: :always_off }} -database_url_config = env!("DATABASE_URL", &ConfigParser.parse_postgresql_uri!/1) +database_url_config = env!("DATABASE_URL", &Electric.Config.parse_postgresql_uri!/1) database_ipv6_config = env!("ELECTRIC_DATABASE_USE_IPV6", :boolean, false) @@ -115,9 +113,9 @@ connection_opts = database_url_config ++ [ipv6: database_ipv6_config] config :electric, connection_opts: Electric.Utils.obfuscate_password(connection_opts) -enable_integration_testing = env!("ELECTRIC_ENABLE_INTEGRATION_TESTING", :boolean, false) -cache_max_age = env!("ELECTRIC_CACHE_MAX_AGE", :integer, 60) -cache_stale_age = env!("ELECTRIC_CACHE_STALE_AGE", :integer, 60 * 5) +enable_integration_testing? = env!("ELECTRIC_ENABLE_INTEGRATION_TESTING", :boolean, nil) +cache_max_age = env!("ELECTRIC_CACHE_MAX_AGE", :integer, nil) +cache_stale_age = env!("ELECTRIC_CACHE_STALE_AGE", :integer, nil) statsd_host = env!("ELECTRIC_STATSD_HOST", :string?, nil) storage_dir = env!("ELECTRIC_STORAGE_DIR", :string, "./persistent") @@ -140,17 +138,12 @@ persistent_kv = raise Dotenvy.Error, message: "ELECTRIC_PERSISTENT_STATE must be one of: MEMORY, FILE" end end, - {Electric.PersistentKV.Filesystem, :new!, root: persistent_state_path} + nil ) -chunk_bytes_threshold = - env!( - "ELECTRIC_SHAPE_CHUNK_BYTES_THRESHOLD", - :integer, - Electric.ShapeCache.LogChunker.default_chunk_size_threshold() - ) +chunk_bytes_threshold = env!("ELECTRIC_SHAPE_CHUNK_BYTES_THRESHOLD", :integer, nil) -{storage_mod, storage_opts} = +storage = env!( "ELECTRIC_STORAGE", fn storage -> @@ -172,7 +165,7 @@ chunk_bytes_threshold = raise Dotenvy.Error, message: "storage must be one of: MEMORY, FILE" end end, - {Electric.ShapeCache.FileStorage, storage_dir: shape_path} + nil ) replication_stream_id = @@ -185,34 +178,32 @@ replication_stream_id = parsed_id end, - "default" + nil ) -storage = {storage_mod, storage_opts} - prometheus_port = env!("ELECTRIC_PROMETHEUS_PORT", :integer, nil) call_home_telemetry_url = env!( "ELECTRIC_TELEMETRY_URL", - &ConfigParser.parse_telemetry_url!/1, - "https://checkpoint.electric-sql.com" + &Electric.Config.parse_telemetry_url!/1, + nil ) system_metrics_poll_interval = env!( "ELECTRIC_SYSTEM_METRICS_POLL_INTERVAL", - &ConfigParser.parse_human_readable_time!/1, - :timer.seconds(5) + &Electric.Config.parse_human_readable_time!/1, + nil ) # The provided database id is relevant if you had used v0.8 and want to keep the storage # instead of having hanging files. We use a provided value as stack id, but nothing else. -provided_database_id = env!("ELECTRIC_DATABASE_ID", :string, "single_stack") +provided_database_id = env!("ELECTRIC_DATABASE_ID", :string, nil) config :electric, provided_database_id: provided_database_id, - allow_shape_deletion: enable_integration_testing, + allow_shape_deletion?: enable_integration_testing?, cache_max_age: cache_max_age, cache_stale_age: cache_stale_age, chunk_bytes_threshold: chunk_bytes_threshold, @@ -223,10 +214,10 @@ config :electric, system_metrics_poll_interval: system_metrics_poll_interval, telemetry_statsd_host: statsd_host, prometheus_port: prometheus_port, - db_pool_size: env!("ELECTRIC_DB_POOL_SIZE", :integer, 20), + db_pool_size: env!("ELECTRIC_DB_POOL_SIZE", :integer, nil), replication_stream_id: replication_stream_id, - replication_slot_temporary?: env!("CLEANUP_REPLICATION_SLOTS_ON_SHUTDOWN", :boolean, false), - service_port: env!("ELECTRIC_PORT", :integer, 3000), + replication_slot_temporary?: env!("CLEANUP_REPLICATION_SLOTS_ON_SHUTDOWN", :boolean, nil), + service_port: env!("ELECTRIC_PORT", :integer, nil), storage: storage, persistent_kv: persistent_kv, - listen_on_ipv6?: env!("ELECTRIC_LISTEN_ON_IPV6", :boolean, false) + listen_on_ipv6?: env!("ELECTRIC_LISTEN_ON_IPV6", :boolean, nil) diff --git a/packages/sync-service/lib/electric.ex b/packages/sync-service/lib/electric.ex index 61c98f9fc1..559c1c1998 100644 --- a/packages/sync-service/lib/electric.ex +++ b/packages/sync-service/lib/electric.ex @@ -1,12 +1,129 @@ defmodule Electric do - @doc """ - Every electric cluster belongs to a particular console database instance + @connection_opts [ + hostname: [type: :string, required: true, doc: "Server hostname"], + port: [type: :integer, required: true, doc: "Server port"], + database: [type: :string, required: true, doc: "Database"], + username: [type: :string, required: true, doc: "Username"], + password: [ + type: {:fun, 0}, + required: true, + doc: + "User password. To prevent leaking of the Pg password in logs and stack traces, you **must** wrap the password with a function." <> + " We provide `Electric.Utils.obfuscate_password/1` which will return the `connection_opts` with a wrapped password value.\n\n" <> + " config :electric, connection_opts: Electric.Utils.obfuscate_password(connection_opts)" + ], + sslmode: [ + type: {:in, [:disable, :allow, :prefer, :require]}, + required: false, + default: :prefer, + doc: + "Connection SSL configuration. See https://www.postgresql.org/docs/current/libpq-ssl.html#LIBPQ-SSL-SSLMODE-STATEMENTS", + type_spec: quote(do: :disable | :allow | :prefer | :require) + ], + ipv6: [ + type: :boolean, + required: false, + default: false, + doc: "Whether to use IPv6 for database connections" + ] + ] + opts_schema = NimbleOptions.new!(@connection_opts) + + @type pg_connection_opts :: [unquote(NimbleOptions.option_typespec(opts_schema))] + + default = fn key -> inspect(Electric.Config.default(key)) end + + @moduledoc """ + + ## Configuration options + + When embedding Electric, the following options are available: + + config :electric, + connection_opts: nil + # Database + provided_database_id: #{default.(:provided_database_id)}, + db_pool_size: #{default.(:db_pool_size)}, + replication_stream_id: #{default.(:replication_stream_id)}, + replication_slot_temporary?: #{default.(:replication_slot_temporary?)}, + # HTTP API + service_port: #{default.(:service_port)}, + allow_shape_deletion?: #{default.(:allow_shape_deletion?)}, + cache_max_age: #{default.(:cache_max_age)}, + cache_stale_age: #{default.(:cache_stale_age)}, + chunk_bytes_threshold: #{default.(:chunk_bytes_threshold)}, + listen_on_ipv6?: #{default.(:listen_on_ipv6?)}, + # Storage + storage_dir: #{default.(:storage_dir)}, + storage: #{default.(:storage)}, + persistent_kv: #{default.(:persistent_kv)}, + # Telemetry + instance_id: #{default.(:instance_id)}, + telemetry_statsd_host: #{default.(:telemetry_statsd_host)}, + prometheus_port: #{default.(:prometheus_port)}, + call_home_telemetry?: #{default.(:call_home_telemetry?)}, + telemetry_url: #{default.(:telemetry_url)}, + + Only the `connection_opts` are required. + + ### Database + + - `connection_opts` - **Required** + #{NimbleOptions.docs(opts_schema, nest_level: 1)}. + - `db_pool_size` - How many connections Electric opens as a pool for handling shape queries (default: `#{default.(:db_pool_size)}`) + - `replication_stream_id` - Suffix for the logical replication publication and slot name (default: `#{default.(:replication_stream_id)}`) + + ### HTTP API + + - `service_port` (`t:integer/0`) - Port that the [HTTP API](https://electric-sql.com/docs/api/http) is exposed on (default: `#{default.(:service_port)}`) + - `allow_shape_deletion?` (`t:boolean/0`) - Whether to allow deletion of Shapes via the HTTP API (default: `#{default.(:allow_shape_deletion?)}`) + - `cache_max_age` (`t:integer/0`) - Default `max-age` for the cache headers of the HTTP API in seconds (default: `#{default.(:cache_max_age)}`s) + - `cache_stale_age` (`t:integer/0`) - Default `stale-age` for the cache headers of the HTTP API in seconds (default: `#{default.(:cache_stale_age)}`s) + - `chunk_bytes_threshold` (`t:integer/0`) - Limit the maximum size in bytes of a shape log response, + to ensure they are cached by upstream caches. (default: `#{default.(:chunk_bytes_threshold)}` (10MiB)). + - `listen_on_ipv6?` (`t:boolean/0`) - Whether the HTTP API should listen on IPv6 as well as IPv4 (default: `#{default.(:listen_on_ipv6?)}`) - This is that database instance id + ### Storage + + - `storage_dir` (`t:String.t/0`) - Path to root folder for storing data on the filesystem (default: `#{default.(:storage_dir)}`) + - `storage` (`t:Electric.ShapeCache.Storage.storage/0`) - Where to store shape logs. Must be a 2-tuple of `{module(), + term()}` where `module` points to an implementation of the + `Electric.ShapeCache.Storage` behaviour. (default: `#{default.(:storage)}`) + - `persistent_kv` (`t:Electric.PersistentKV.t/0`) - A mfa that when called constructs an implementation of + the `Electric.PersistentKV` behaviour, used to store system state (default: `#{default.(:persistent_kv)}`) + + ### Telemetry + + - `instance_id` (`t:binary/0`) - A unique identifier for the Electric instance. Set this to + enable tracking of instance usage metrics across restarts, otherwise will be + randomly generated at boot (default: a randomly generated UUID). + - `telemetry_statsd_host` (`t:String.t/0`) - If set, send telemetry data to the given StatsD reporting endpoint (default: `#{default.(:telemetry_statsd_host)}`) + - `prometheus_port` (`t:integer/0`) - If set, expose a prometheus reporter for telemetry data on the specified port (default: `#{default.(:prometheus_port)}`) + - `call_home_telemetry?` (`t:boolean/0`) - Allow [anonymous usage + data](https://electric-sql.com/docs/reference/telemetry#anonymous-usage-data) + about the instance being sent to a central checkpoint service (default: `true` for production) + - `telemetry_url` (`t:URI.t/0`) - Where to send the usage data (default: `#{default.(:telemetry_url)}`) + + ### Deprecated + + - `provided_database_id` (`t:binary/0`) - The provided database id is relevant if you had + used v0.8 and want to keep the storage instead of having hanging files. We + use a provided value as stack id, but nothing else. + """ + + require Logger + + @doc false + def connection_opts_schema do + @connection_opts + end + + @doc """ + `instance_id` is used to track a particular server's telemetry metrics. """ @spec instance_id() :: binary | no_return def instance_id do - Application.fetch_env!(:electric, :instance_id) + Electric.Config.fetch_env!(:instance_id) end @type relation :: {schema :: String.t(), table :: String.t()} diff --git a/packages/sync-service/lib/electric/application.ex b/packages/sync-service/lib/electric/application.ex index b0dd3ff320..f9b885024a 100644 --- a/packages/sync-service/lib/electric/application.ex +++ b/packages/sync-service/lib/electric/application.ex @@ -1,5 +1,6 @@ defmodule Electric.Application do use Application + require Config @doc """ @@ -12,29 +13,34 @@ defmodule Electric.Application do def start(_type, _args) do :erlang.system_flag(:backtrace_depth, 50) + Electric.Config.ensure_instance_id() Electric.Telemetry.Sentry.add_logger_handler() # We have "instance id" identifier as the node ID, however that's generated every runtime, # so isn't stable across restarts. Our storages however scope themselves based on this stack ID # so we're just hardcoding it here. - stack_id = Application.get_env(:electric, :provided_database_id, "single_stack") + stack_id = Electric.Config.get_env(:provided_database_id) + + storage = Electric.Config.get_env(:storage) router_opts = [ long_poll_timeout: 20_000, - max_age: Application.fetch_env!(:electric, :cache_max_age), - stale_age: Application.fetch_env!(:electric, :cache_stale_age), - allow_shape_deletion: Application.fetch_env!(:electric, :allow_shape_deletion) + max_age: Electric.Config.get_env(:cache_max_age), + stale_age: Electric.Config.get_env(:cache_stale_age), + allow_shape_deletion: Electric.Config.get_env(:allow_shape_deletion?) ] ++ Electric.StackSupervisor.build_shared_opts( stack_id: stack_id, stack_events_registry: Registry.StackEvents, - storage: Application.fetch_env!(:electric, :storage) + storage: storage ) - {kv_module, kv_fun, kv_params} = Application.fetch_env!(:electric, :persistent_kv) + {kv_module, kv_fun, kv_params} = + Electric.Config.get_env(:persistent_kv) + persistent_kv = apply(kv_module, kv_fun, [kv_params]) - replication_stream_id = Application.fetch_env!(:electric, :replication_stream_id) + replication_stream_id = Electric.Config.get_env(:replication_stream_id) publication_name = "electric_publication_#{replication_stream_id}" slot_name = "electric_slot_#{replication_stream_id}" @@ -52,27 +58,28 @@ defmodule Electric.Application do Enum.concat([ [ {Registry, name: Registry.StackEvents, keys: :duplicate}, - {Electric.StackSupervisor, - stack_id: stack_id, - stack_events_registry: Registry.StackEvents, - connection_opts: Application.fetch_env!(:electric, :connection_opts), - persistent_kv: persistent_kv, - replication_opts: [ - publication_name: publication_name, - slot_name: slot_name, - slot_temporary?: Application.fetch_env!(:electric, :replication_slot_temporary?) - ], - pool_opts: [pool_size: Application.fetch_env!(:electric, :db_pool_size)], - storage: Application.fetch_env!(:electric, :storage), - chunk_bytes_threshold: Application.fetch_env!(:electric, :chunk_bytes_threshold)}, - {Electric.Telemetry, - stack_id: stack_id, storage: Application.fetch_env!(:electric, :storage)}, + { + Electric.StackSupervisor, + stack_id: stack_id, + stack_events_registry: Registry.StackEvents, + connection_opts: Electric.Config.fetch_env!(:connection_opts), + persistent_kv: persistent_kv, + replication_opts: [ + publication_name: publication_name, + slot_name: slot_name, + slot_temporary?: Electric.Config.get_env(:replication_slot_temporary?) + ], + pool_opts: [pool_size: Electric.Config.get_env(:db_pool_size)], + storage: storage, + chunk_bytes_threshold: Electric.Config.get_env(:chunk_bytes_threshold) + }, + {Electric.Telemetry, stack_id: stack_id, storage: storage}, {Bandit, plug: {Electric.Plug.Router, router_opts}, - port: Application.fetch_env!(:electric, :service_port), + port: Electric.Config.get_env(:service_port), thousand_island_options: http_listener_options()} ], - prometheus_endpoint(Application.fetch_env!(:electric, :prometheus_port)) + prometheus_endpoint(Electric.Config.get_env(:prometheus_port)) ]) Supervisor.start_link(children, strategy: :one_for_one, name: Electric.Supervisor) @@ -92,7 +99,7 @@ defmodule Electric.Application do end defp http_listener_options do - if Application.get_env(:electric, :listen_on_ipv6?, false) do + if Electric.Config.get_env(:listen_on_ipv6?) do [transport_options: [:inet6]] else [] diff --git a/packages/sync-service/lib/electric/config_parser.ex b/packages/sync-service/lib/electric/config.ex similarity index 73% rename from packages/sync-service/lib/electric/config_parser.ex rename to packages/sync-service/lib/electric/config.ex index 6d8c7ddd67..30aec0442f 100644 --- a/packages/sync-service/lib/electric/config_parser.ex +++ b/packages/sync-service/lib/electric/config.ex @@ -1,4 +1,114 @@ -defmodule Electric.ConfigParser do +defmodule Electric.Config.Defaults do + @moduledoc false + + # we want the default storage and kv implementations to honour the + # `:storage_dir` configuration setting so we need to use runtime-evaluated + # functions to get them. Since you can't embed anoymous functions these + # functions are used instead. + + @doc false + def storage do + {Electric.ShapeCache.FileStorage, storage_dir: storage_dir("shapes")} + end + + @doc false + def persistent_kv do + {Electric.PersistentKV.Filesystem, :new!, root: storage_dir("state")} + end + + defp storage_dir(sub_dir) do + Path.join(storage_dir(), sub_dir) + end + + defp storage_dir do + Electric.Config.get_env(:storage_dir) + end +end + +defmodule Electric.Config do + require Logger + + @build_env Mix.env() + + @defaults [ + # Database + provided_database_id: "single_stack", + db_pool_size: 20, + replication_stream_id: "default", + replication_slot_temporary?: false, + # HTTP API + cache_max_age: 60, + cache_stale_age: 60 * 5, + chunk_bytes_threshold: Electric.ShapeCache.LogChunker.default_chunk_size_threshold(), + allow_shape_deletion?: false, + service_port: 3000, + listen_on_ipv6?: false, + # Storage + storage_dir: "./persistent", + storage: &Electric.Config.Defaults.storage/0, + persistent_kv: &Electric.Config.Defaults.persistent_kv/0, + # Telemetry + instance_id: nil, + prometheus_port: nil, + call_home_telemetry?: @build_env == :prod, + telemetry_statsd_host: nil, + telemetry_url: URI.new!("https://checkpoint.electric-sql.com"), + system_metrics_poll_interval: :timer.seconds(5) + ] + + def default(key) do + case Keyword.fetch!(@defaults, key) do + fun when is_function(fun, 0) -> fun.() + value -> value + end + end + + @doc false + @spec ensure_instance_id() :: :ok + # the instance id needs to be consistent across calls, so we do need to have + # a value in the config, even if it's not configured by the user. + def ensure_instance_id do + case get_env(:instance_id, nil) do + nil -> + instance_id = generate_instance_id() + + Logger.info("Setting electric instance_id: #{instance_id}") + Application.put_env(:electric, :instance_id, instance_id) + + id when is_binary(id) -> + :ok + end + end + + defp generate_instance_id do + Electric.Utils.uuid4() + end + + @spec get_env(Application.key()) :: Application.value() + def get_env(key) do + get_env(key, default(key)) + end + + defp get_env(key, nil) do + Application.get_env(:electric, key, nil) + end + + defp get_env(key, default) do + # handle the case where the config value was set in runtime.exs but to + # `nil` because of a missing env var. This allows us to just use `nil` + # as the default config values in runtime.exs so avoiding hard-coding + # defaults all over the place. + case Application.get_env(:electric, key, default) do + nil -> default + value -> value + end + end + + @spec fetch_env!(Application.key()) :: Application.value() + def fetch_env!(key) do + Application.fetch_env!(:electric, key) + end + @doc ~S""" Parse a PostgreSQL URI into a keyword list. diff --git a/packages/sync-service/lib/electric/stack_supervisor.ex b/packages/sync-service/lib/electric/stack_supervisor.ex index e8d94c872a..71c355a3cd 100644 --- a/packages/sync-service/lib/electric/stack_supervisor.ex +++ b/packages/sync-service/lib/electric/stack_supervisor.ex @@ -38,15 +38,7 @@ defmodule Electric.StackSupervisor do connection_opts: [ type: :keyword_list, required: true, - keys: [ - hostname: [type: :string, required: true], - port: [type: :integer, required: true], - database: [type: :string, required: true], - username: [type: :string, required: true], - password: [type: {:fun, 0}, required: true], - sslmode: [type: :atom, required: false], - ipv6: [type: :boolean, required: false] - ] + keys: Electric.connection_opts_schema() ], replication_opts: [ type: :keyword_list, diff --git a/packages/sync-service/lib/electric/telemetry.ex b/packages/sync-service/lib/electric/telemetry.ex index fbd8d40ca7..7596b9eba9 100644 --- a/packages/sync-service/lib/electric/telemetry.ex +++ b/packages/sync-service/lib/electric/telemetry.ex @@ -8,11 +8,12 @@ defmodule Electric.Telemetry do end def init(opts) do - system_metrics_poll_interval = Application.get_env(:electric, :system_metrics_poll_interval) + system_metrics_poll_interval = + Electric.Config.get_env(:system_metrics_poll_interval) - statsd_host = Application.fetch_env!(:electric, :telemetry_statsd_host) - prometheus? = not is_nil(Application.fetch_env!(:electric, :prometheus_port)) - call_home_telemetry? = Application.fetch_env!(:electric, :call_home_telemetry?) + statsd_host = Electric.Config.get_env(:telemetry_statsd_host) + prometheus? = not is_nil(Electric.Config.get_env(:prometheus_port)) + call_home_telemetry? = Electric.Config.get_env(:call_home_telemetry?) [ {:telemetry_poller, diff --git a/packages/sync-service/lib/electric/telemetry/call_home_reporter.ex b/packages/sync-service/lib/electric/telemetry/call_home_reporter.ex index f698d7bf46..f434325a00 100644 --- a/packages/sync-service/lib/electric/telemetry/call_home_reporter.ex +++ b/packages/sync-service/lib/electric/telemetry/call_home_reporter.ex @@ -32,7 +32,7 @@ defmodule Electric.Telemetry.CallHomeReporter do :ok end - defp telemetry_url, do: Application.fetch_env!(:electric, :telemetry_url) + defp telemetry_url, do: Electric.Config.get_env(:telemetry_url) def print_stats(name \\ __MODULE__) do GenServer.call(name, :print_stats) diff --git a/packages/sync-service/test/electric/config_parser_test.exs b/packages/sync-service/test/electric/config_parser_test.exs deleted file mode 100644 index 2c1e9840bf..0000000000 --- a/packages/sync-service/test/electric/config_parser_test.exs +++ /dev/null @@ -1,5 +0,0 @@ -defmodule Electric.ConfigParserTest do - use ExUnit.Case, async: true - - doctest Electric.ConfigParser, import: true -end diff --git a/packages/sync-service/test/electric/config_test.exs b/packages/sync-service/test/electric/config_test.exs new file mode 100644 index 0000000000..e42a4455a4 --- /dev/null +++ b/packages/sync-service/test/electric/config_test.exs @@ -0,0 +1,5 @@ +defmodule Electric.ConfigTest do + use ExUnit.Case, async: true + + doctest Electric.Config, import: true +end