Image model reference loader reference

August 31, 2026 ยท View on GitHub

Topics: generation, workers

horde.model_reference holds the set of image models this service will price, validate, and schedule against. One elected AI-Horde instance refreshes it hourly and publishes a complete, versioned snapshot to central Redis. Every API instance reads that same snapshot into local memory.

Fleet distribution

Redis key image_model_reference:snapshot:v1 is the fleet's last-known-good image reference. One document contains the final canonical-plus-pending model view and the baseline catalog, with a SHA-256 revision over both. Replacing that key is atomic, so consumers cannot observe half a publication.

REDIS_IP is the authoritative read and lease endpoint. After its fenced transaction succeeds, the publisher copies the same immutable document to every reachable independent master in REDIS_SERVERS, preserving AI-Horde's active/passive failover topology. Redis key image_model_reference:publish_sequence:v1 carries the monotonically increasing generation on each server; a delayed older publisher cannot regress a passive server. Consumers continue to read only the current REDIS_IP, and the host-local db6 cache is never involved.

At cold start, an instance first reads Redis. When the key is absent, contenders use a fenced Redis lease and exactly one fetches the remote sources; the others wait for its publication. After startup, the AI-Horde quorum owner checks once a minute whether the served snapshot is degraded or more than an hour old and, if so, performs the remote refresh; every instance polls Redis for a new revision. A newly elected owner therefore takes over publication within a minute rather than a full interval. The per-host Redis cache is deliberately bypassed for this control-plane value.

A remote, validation, or pending-model failure never clears or replaces the Redis value. Running instances retain their in-memory snapshot during Redis failure. A process without central Redis fails startup rather than independently fetching a potentially divergent view. Cold-start losers continue contending until an abandoned publication lease can expire and one of them takes over; the effective bootstrap timeout is therefore never shorter than the lease plus five seconds.

When the whole bootstrap window passes with no snapshot published (the PRIMARY is unreachable and Redis holds nothing), contenders get one further lease-long window in which a publication may be degraded: HMR's GitHub fallback for the canonical models, the baseline catalog packaged with horde_model_reference, and no pending models. The document carries degraded: true, every process that applies it logs an error, and the elected publisher treats a degraded document as always due, so it keeps retrying (every ten seconds on failure) until the PRIMARY answers and a healthy document replaces it. A degraded document is never published while any snapshot already exists.

Each process reports horde.model_reference.snapshot_age (seconds since the served document was published) and horde.model_reference.snapshot_degraded on every Redis poll, and warns hourly once the served snapshot is older than three hours, which is three missed publisher cycles. Unknown top-level fields in a snapshot are ignored with a warning so an older consumer keeps loading a newer publisher's document during a rolling deploy.

Where the models come from

The loader drives horde_model_reference's ModelReferenceManager in REPLICA mode. Two sources are merged on every refresh:

  • The canonical source (horde): the PRIMARY service named by HORDE_MODEL_REFERENCE_PRIMARY_API_URL. HMR may obtain a GitHub fallback internally, but the publisher detects that outcome and refuses to replace the fleet's last-known-good Redis snapshot.
  • The pending source (pending): models sitting in the PRIMARY's pending queue. These are the beta models. They carry no special restrictions; a pending model is a known model.

Pending is listed ahead of canonical, so a pending record wins a name collision. That is how a model is revised while it is still in beta.

The publisher constructs HMR with PrefetchStrategy.NONE; it does not run HMR's all-category prefetch. A publication reads only the image baseline export, canonical image_generation category, and (when enabled) pending image_generation category. ASYNC prefetch is intentionally not used: it warms every category and requires an asyncio event loop, while this publisher runs from the synchronous Flask/background-thread lifecycle. Startup rejects an HMR singleton that another importer previously constructed with a different strategy, rather than silently inheriting LAZY.

Text models remain outside this pipeline. AI-Horde continues to read the legacy standalone AI-Horde-text-model-reference JSON into each process at startup and hourly, dropping any entry without a numeric parameter count rather than rejecting the payload; HMR's text categories are not queried by the fleet image publisher.

Adding a model to the PRIMARY needs no change here, and neither does adding a baseline: the baseline catalog is served alongside the models.

The publisher rejects an empty model reference, an empty baseline catalog, or a document whose content does not match its revision before mutating Redis. If a model names a baseline missing from the first catalog read, it re-fetches the catalog after fixing the model view to cover PRIMARY's baseline-before-model publication race.

The baseline catalog

The same manager serves a catalog of image baselines, exposed as model_reference.baseline_record(baseline) and returning an ImageBaselineRecord or None. It states what exists for a model family and what the horde charges for it, and is what baseline policy reads. The hourly refresh re-fetches it from the PRIMARY, so a baseline published or repriced after this process started is picked up without a deployment. A failed re-fetch is logged and leaves the complete Redis snapshot serving.

What the loader exposes

Records stay typed as ImageGenerationModelRecord in memory:

MemberMeaning
referencedict[str, ImageGenerationModelRecord], keyed by model name. Empty until a fleet snapshot is applied.
stable_diffusion_namesEvery image model name. No baseline allowlist is applied.
nsfw_modelsImage and text models flagged NSFW.
controlnet_modelsAlways empty. The reference no longer carries a controlnet model type; the attribute is kept for callers.
get_model_baseline(name)The record's baseline, verbatim.
get_all_model_baselines(names)The set of baselines those names resolve to.
get_model_requirements(name)The record's requirements, or {}.
baseline_record(baseline)The served baseline record, or None where the catalog has no such name.

A model the reference has never heard of still resolves to a baseline, from the suffix its name declares: [SDXL], [Flux], [Qwen], [ZModel] and [ZImage], falling through to stable_diffusion_1. Customizer-role users can request such a name, and it must still be priced. An uncatalogued baseline is accepted for plain generation but receives no baseline-dependent workflow capabilities by default.

A refresh stages the baseline catalog and model records before publishing them as one copy-on-write snapshot, so request readers never see a new model paired with the previous catalog. If either side fails to fetch or validate, the previous complete snapshot keeps serving traffic.

Environment

VariableDefaultEffect
HORDE_MODEL_REFERENCE_PRIMARY_API_URLhttps://models.aihorde.net/apiThe PRIMARY the elected publisher reads. Fleet publication requires this service; GitHub fallback is not allowed to replace the last-known-good snapshot.
AIWORKER_CACHE_HOMEmodelsHMR's on-disk cache on the elected publisher. API consumers do not read it; a relative value resolves against the process working directory.
HORDE_MODEL_REFERENCE_BOOTSTRAP_TIMEOUT195Minimum seconds a cold-starting API process waits for the bootstrap publisher to populate Redis. The effective value is extended when necessary so it exceeds the publication lease by five seconds.
HORDE_MODEL_REFERENCE_PUBLISH_LOCK_SECONDS180Redis publication-lease lifetime. A fetch that outlives its lease is fenced out and cannot overwrite a newer snapshot.
HORDE_BETA_MODEL_CATEGORIESimage_generationComma-separated categories to merge pending models into. An empty value disables beta. An unrecognized value is logged and skipped.
HORDE_BETA_MODELS_API_KEY0000000000A reader-level AI-Horde key for the pending reads. The PRIMARY accepts the anonymous key. An empty value disables beta.

horde_model_reference reads its own HORDE_MODEL_REFERENCE_* settings directly. AI-Horde detects and rejects HMR's GitHub fallback during fleet publication, because independently replacing a live PRIMARY revision with the fallback would violate the last-known-good contract.

Database mirror

store_known_image_models mirrors the reference into the known_image_models table each cycle. Columns the record leaves optional but the table declares non-nullable (version, style, tags) receive empty values, and features_not_supported has no counterpart in the record schema, so it is always cleared.