# `Perplexed.Search.SearXNG.Instances`
[🔗](https://github.com/agoodway/perplexed/blob/v0.2.0/lib/perplexed/search/searxng/instances.ex#L1)

The live set of public SearXNG instances, discovered instead of
hard-coded. Set `searxng_instances: :auto` and `Perplexed.Search.SearXNG`
asks this store for its instances.

The store starts empty. The first search that needs it runs
`Perplexed.Search.SearXNG.Directory.discover/1` (fetch searx.space,
filter, probe each start page, seed the pool) and waits for it;
searches that arrive meanwhile wait on the same discovery rather than
starting their own. After that it refreshes in the background every
`searxng_refresh_ms` (default daily), keeping the last good list if a
refresh fails and retrying a failed refresh sooner. Discovery options
come from the `searxng_discovery` setting, such as
`[countries: ["US", "CA"], max_median_ms: 2_500]`.

Discovery runs in a task under `Perplexed.TaskSupervisor`, so a slow
searx.space never blocks the store, and a crash in it is logged as a
failed refresh. Each finished refresh emits
`[:perplexed, :searxng, :instances]` with `count` and metadata `result`.

# `status`

```elixir
@type status() :: %{
  count: non_neg_integer(),
  refreshed_at: DateTime.t() | nil,
  refreshing?: boolean(),
  last_error: term()
}
```

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `entries`

```elixir
@spec entries(keyword()) :: [Perplexed.Search.SearXNG.Directory.entry()]
```

Like `urls/1`, with each instance's directory entry and probe.

# `refresh`

```elixir
@spec refresh(keyword()) :: [Perplexed.Search.SearXNG.Directory.entry()]
```

Refreshes now. With `await: true`, waits and returns the entries;
otherwise starts the refresh in the background and returns `[]`.

# `start_link`

```elixir
@spec start_link(keyword()) :: GenServer.on_start()
```

Starts the store. Options: `:name` (default `Perplexed.Search.SearXNG.Instances`),
`:discovery` (options for `Directory.discover/1`, merged over the
`searxng_discovery` setting), `:refresh_ms` and `:retry_ms`.

# `status`

```elixir
@spec status(keyword()) :: status()
```

What the store holds and when it last refreshed.

# `urls`

```elixir
@spec urls(keyword()) :: [String.t()]
```

The live instances' URLs, fastest first, discovering them first when the
store has never been filled (waiting up to `:await_ms`, default
120000). Options: `:store`, `:await_ms`.

---

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