Schedule icon
Search icon
If icon
Log icon
SlackIncomingWebhook icon

Algolia Canary Search Availability Sentinel

Run a canary search against Algolia and alert Slack the instant a query that should always match comes back empty.

Categories
DataInfrastructure

An Algolia index that silently goes empty - a broken reindex job, an accidental bulk delete, a sync pipeline that stopped halfway - produces no error on its own; the search API still responds 200 OK, it just returns zero hits. Customers see a blank results page long before anyone notices in a dashboard. This blueprint runs a canary search on a schedule and alerts Slack the moment a query that should reliably match comes back under a configured threshold, or the index target itself is unreachable.

How it works

  1. periodic_canary_search (io.kestra.plugin.core.trigger.Schedule) runs every 15 minutes, explicitly passing index_name, canary_query, and min_expected_hits through its own inputs: block so the flow is self-contained when the trigger fires. Shipped disabled so a manual run can be verified first.
  2. probe_canary_search (io.kestra.plugin.algolia.Search) issues a single read-only query against the target index and captures Algolia's own nbHits total match count.
  3. evaluate_index_health (io.kestra.plugin.core.flow.If) branches on whether nbHits meets or exceeds min_expected_hits.
    • then (HEALTHY): log_index_healthy records the pass.
    • else (INDEX_EMPTY_OR_DEGRADED): alert_index_unhealthy reports the shortfall to Slack with the exact hit count and threshold.
  4. log_audit_complete always runs last, printing the final nbHits regardless of which branch fired.
  5. The errors block alerts Slack separately if the search call itself throws - a deleted index, an invalid application ID or API key, or an unreachable API - deliberately kept distinct from an empty-but-existing index, since the two failure modes need different fixes.

What you get

  • A synthetic, customer's-eye-view check: the same kind of query a real user would run, rather than an internal record-count API that can stay accurate while search itself is broken.
  • A clean separation between "index exists but has nothing matching" (INDEX_EMPTY_OR_DEGRADED, handled by the If branch) and "index target itself is gone or credentials are wrong" (handled by the flow-level errors block) - two different incidents that call for different responses.
  • A configurable min_expected_hits threshold so a seeded heartbeat record (or any query known to always match at least N records) can be audited precisely, not just checked for "any result at all."
  • A worked example of io.kestra.plugin.algolia.Search, a plugin with no prior blueprint coverage of its read path in this repository (the one existing Algolia blueprint covers index sync, not search availability).

Who it's for

  • Teams running Algolia-backed search or autocomplete who want to know the moment it silently stops returning results, instead of waiting for a support ticket about "search is broken."
  • Data/platform engineers who own the ingestion pipeline feeding an Algolia index and want an independent, pipeline-agnostic check that the index itself is still serving - one that keeps working even if the ingestion job's own success/failure status is misleading.
  • Anyone evaluating the Algolia plugin who wants a worked example of its read-only Search task used for monitoring rather than for building search UI.

Why orchestrate this with Kestra

Algolia has no built-in "alert me if this query stops matching" primitive - its own dashboard shows search analytics and index size, but nothing that proactively watches a specific query's hit count over time. Kestra supplies the schedule, the HEALTHY/INDEX_EMPTY_OR_DEGRADED classification as a first-class branch, the execution history showing exactly when the canary first failed, and a clear separation between "empty index" and "unreachable index" failure modes.

Prerequisites

  • An Algolia account and index with at least one record (the Free plan requires no credit card and is permanently free, as of 2026 capped at 50,000 records and 10,000 search requests per month - more than sufficient for this sentinel's query volume).
  • An Algolia Application ID and Admin API Key (update ALGOLIA_APP_ID / ALGOLIA_API_KEY secrets).
  • A Slack incoming webhook for alerts.

Local testing: Algolia is a hosted SaaS search service with no official self-hosted or Docker emulator - the Search task always calls the real Algolia API. A free, no-credit-card account is sufficient to exercise this blueprint end to end; no paid enterprise tier or portal account is required.

Secrets

  • ALGOLIA_APP_ID / ALGOLIA_API_KEY: credentials for io.kestra.plugin.algolia.Search, matching the plugin's own documented example usage of secret('ALGOLIA_APP_ID') / secret('ALGOLIA_API_KEY').
  • SLACK_WEBHOOK_URL: Slack incoming webhook used by alert_index_unhealthy and the errors block.
  • In Kestra OSS (no Enterprise secrets backend), secrets are supplied as environment variables prefixed SECRET_, base64-encoded - for example SECRET_ALGOLIA_API_KEY=$(echo -n '<your-api-key>' | base64) - and read back in flows with {{ secret('NAME') }}.

Inputs

  • index_name (STRING, default <your-algolia-index>, must be replaced): the index audited.
  • canary_query (STRING, default ""): the query text expected to reliably match. An empty string matches every record in the index (the Search task's own documented default behavior), making it the simplest possible canary - any result at all proves the index is reachable and non-empty.
  • min_expected_hits (INT, default 1): the floor nbHits must meet or exceed to be classified HEALTHY.

Outputs

  • outputs.probe_canary_search.nbHits (Integer): Algolia's own total match count for the query (verified field from the Search task's Output class).
  • outputs.probe_canary_search.hits (List): up to hitsPerPage matching records themselves, capped at 1 in this blueprint since only the count is used for classification.

Quick start

  1. Create a free Algolia account and index, add at least one record.
  2. Add the ALGOLIA_APP_ID, ALGOLIA_API_KEY, and SLACK_WEBHOOK_URL secrets.
  3. Run the flow manually with canary_query left empty and confirm log_index_healthy fires with nbHits matching your record count.
  4. Temporarily set canary_query to a term you know does not exist, or min_expected_hits above your real record count, and re-run to confirm alert_index_unhealthy fires.
  5. Set index_name to a nonexistent index and re-run to confirm the errors block fires separately from the HEALTHY/INDEX_EMPTY_OR_DEGRADED branches.
  6. Enable periodic_canary_search once you trust the check against your real index.

How to extend

  • Loop over several index_name / canary_query pairs with io.kestra.plugin.core.flow.Loop to audit every index in an Algolia application in one run.
  • If your records carry a numeric timestamp attribute, add a second Search task with a numericFilters param (for example updatedAt > <N minutes ago>) to additionally audit ingestion freshness, not just index non-emptiness - kept out of this sentinel since it depends on a schema attribute this blueprint cannot assume exists.
  • Add a remediation branch that re-triggers the upstream sync pipeline flow via io.kestra.plugin.core.flow.Subflow when INDEX_EMPTY_OR_DEGRADED fires, behind an explicit approval gate.

Pitfalls

  • nbHits reflects total matches across the whole index, not just the returned page. hitsPerPage: 1 keeps the response small without affecting the count used for classification - verified directly from the Search task's source, which reads response.getNbHits() independently of hitsPerPage.
  • An empty canary_query matches everything, which is the weakest possible canary - it only proves the index is non-empty, not that any particular record type is present. For a stronger check, seed a dedicated heartbeat record with a unique, stable attribute value and query for that instead.
  • Algolia's API enforces rate and quota limits on the Free plan (10,000 search requests/month as of 2026) - a 15-minute schedule uses roughly 2,880 requests/month from this sentinel alone, leaving headroom for normal application traffic on a Free-plan index, but this should be accounted for on a shared production index.
  • This blueprint is UNTESTED against a live Algolia index. The task class, its nbHits/hits output fields, and the empty-query-matches-all behavior are taken verbatim from the Algolia plugin's own source and Javadoc - but no Kestra engine was run to execute this flow end to end.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.