# `GeoGenius.Application`
[🔗](https://github.com/agoodway/geo_genius/blob/main/lib/geo_genius/application.ex#L1)

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_genius`
    cannot see a Repo that has not started yet. Placing `Preflight` here
    would run its verification query before any Repo exists to query.
  * `Preflight` skips itself for a Repo pooled through
    `Ecto.Adapters.SQL.Sandbox` because 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 raise
    `DBConnection.OwnershipError` and abort the host's entire test suite
    before its first `setup` block 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.TaskSupervisor

with `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.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
