Per-connection supervisor using :rest_for_one strategy.
Manages a Finch pool (unless the config names an existing one with
:finch_name) and a BatchWriter GenServer for a
single named InfluxDB connection with crash isolation.
On start, registers the connection the client initialised in
InfluxElixir.Connection so it can be resolved by name
from any process via Connection.fetch!/1 or the facade. The
registration is taken down, and the client's state for the connection
released, whenever the supervisor stops, including when it gives up after
too many restarts or a child fails to start: a name never resolves to a
connection that is not running. A call made in the moment between the
registration and the pool starting is {:error, {:connection_error, :no_pool}},
never a raise.
If the Finch pool crashes, the connection's BatchWriter (at most one)
restarts with it, since it depends on the pool. A BatchWriter crash
does NOT take down the pool. The writer is started with the connection's
name (connection: name), so it writes through whatever is registered
and its child spec, which supervisors print when a start fails, holds no
token.
Children stop in reverse start order, so on shutdown the BatchWriter writes its buffer while the Finch pool is still up.
If this supervisor is killed outright, its children outlive it for a
moment (they stop when they see it exit) and still hold their registered
names. They stop together, not in order, so the writer's last write can
find the connection already released and the pool gone, and then the
buffer is lost. InfluxElixir.remove_connection/1 stops them in
order. A restart waits for
those names to be released, up to 15000 ms each,
before starting new children: starting at once failed with
:already_started, and the repeated failures took the top-level
supervisor, and every other connection, down with it.
Failures to start
A config the client refuses makes start_link/1 return {:error, reason},
and InfluxElixir.add_connection/2 {:error, {reason, child_spec}};
nothing is started or registered:
InfluxElixir.Client.HTTP: the%NimbleOptions.ValidationError{}ofInfluxElixir.Config.validate/1;InfluxElixir.Client.Local: the%ArgumentError{}thatInfluxElixir.Client.Local.start/1raises for the same options;- any client: the
reasonof aninit_connection/1that returns{:error, reason}.
The :token never appears in that error or in the logs of a failed start:
the child spec and the supervisor's argument carry it opaque (inspect/1
prints #InfluxElixir.ConnectionSupervisor.Secret<...>), and a :token
that is not a string is refused without its value.
Summary
Functions
The child spec that starts a ConnectionSupervisor for config, with its :token
made opaque (see "Failures to start").
Starts a ConnectionSupervisor for a named connection.
Functions
@spec child_spec(keyword()) :: Supervisor.child_spec()
The child spec that starts a ConnectionSupervisor for config, with its :token
made opaque (see "Failures to start").
@spec start_link(keyword()) :: Supervisor.on_start() | {:error, {:invalid_options, term()}}
Starts a ConnectionSupervisor for a named connection.
Config
:name- connection name (atom, required):host- InfluxDB host (no scheme):token- authentication token:database- default database for writes/queries:databases- list of database names (seeInfluxElixir.Config):pool_size- Finch connection pool size (default: 10):finch_name- an existing Finch pool to use; no per-connection pool is started:batch_writer- keyword options for anInfluxElixir.Write.BatchWriterchild; omitted means no writer- any other
InfluxElixir.Configoption (:api_version,:scheme, ...)
When the configured client is InfluxElixir.Client.HTTP the config is
validated with InfluxElixir.Config.validate/1, so a typo such as
default_database: fails at startup instead of being silently ignored:
start_link/1 returns the {:error, %NimbleOptions.ValidationError{}}
it gave (see "Failures to start"). InfluxElixir.Client.Local needs no
host, so its config is not validated against that schema.