Starts GeoGenius's own supervision tree: an execution-guardian supervisor
and, unless a host supplies one, a Task.Supervisor registered as
GeoGenius.TaskSupervisor.
GeoGenius.Runners.Task uses that supervisor when a host has configured
nothing of its own, so an asynchronous import works with zero host
configuration. When config :geo_genius, :task_supervisor is already set
at boot, this tree omits only that task supervisor: the host has committed
to supplying its own. The guardian remains package-owned because it
monitors executions under every backend, including PgFlow and a host task
supervisor.
Do not add GeoGenius.Preflight to this tree. It must stay a child the
host places, immediately after its own Repo, for two reasons this
library has already paid to learn:
- A dependency application starts before its host's, so
:geo_geniuscannot see a Repo that has not started yet. PlacingPreflighthere would run its verification query before any Repo exists to query. Preflightskips itself for a Repo pooled throughEcto.Adapters.SQL.Sandboxbecause the supervisor starts it from a process holding no checked-out connection; started from here instead of the host's own tree, that same query would raiseDBConnection.OwnershipErrorand abort the host's entire test suite before its firstsetupblock runs.
A Task.Supervisor carries neither risk at boot: it needs nothing to
start, starts empty, and does no work until a host calls
GeoGenius.import/1 -- by which time the host's own Repo is already up.
Shutdown is the opposite story, and it is backwards by default.
Applications start in dependency order and stop in the reverse of that
order: :geo_genius starts before its host, so it stops after it. On
System.stop/1 (or any ordinary release shutdown), the host's own
supervision tree -- Repo included -- finishes stopping first, and only
then is this tree told to stop. An import task still running at that
moment keeps running, against a Repo that is already gone, for the entire
length of the host's own shutdown: every phase call it makes fails,
repeatedly, against a connection that no longer exists. This is not a
hypothetical corner case -- it is what actually happens with no
configuration at all, because the library's own supervisor sits outside
the host's tree entirely and is stopped only after the host's tree
already has been.
A host that cares about shutdown order takes the override instead, and places the supervisor correctly:
config :geo_genius, :task_supervisor, MyApp.TaskSupervisorwith MyApp.TaskSupervisor listed after MyApp.Repo in the host's own
children list. Supervisors terminate children in the reverse of their
start order, so a later-listed TaskSupervisor -- and every task under it
-- is stopped before Repo is, instead of after. For a host running
import work under this backend, this is not merely a matter of taste in
where the process lives; it is the only supervision arrangement whose
shutdown ordering is actually correct, and this library cannot arrange it
from the outside.
Killing a running import task this way is still not graceful: a Task
does not trap exits, so it dies wherever it happens to be and cannot clean
up its staging table. The independently supervised execution guardian
monitors that task, however. With the host-owned ordering above, the task
dies while both the guardian and Repo are still alive, so the guardian
records a durable failure using the exact executor identity before the
Repo stops. The executor is never transferred or taken over.
The package-owned default cannot make the same shutdown guarantee. The
host Repo has already stopped by the time the dependency application's
task and guardian supervisors shut down, so the guardian may be unable to
record the task's death. Whole-VM or whole-node loss has the same limit:
no surviving local process exists to write the outcome. In those cases a
stale heartbeat remains diagnostic; an operator records the abandoned
attempt's failure and starts a new one explicitly with
GeoGenius.retry_failed/2. See GeoGenius.Runners.Task's moduledoc.
A host can list the pids of tasks currently running under either
supervisor with Task.Supervisor.children/1 -- bare pids, not run ids,
and, under the override, potentially mixed with unrelated tasks the host
started under that same supervisor itself. A host that wants to see
actual import runs queries import_run (or GeoGenius.status/2)
instead.