New to Kestra?
Use blueprints to kickstart your first workflows.
Verify a Typesense catalog rebuild landed with Kestra. DocumentGet reads a sentinel document, Python checks rebuilt_at, and Discord hears when it is stale.
A green rebuild execution proves the pipeline ran; it does not prove the index changed. This blueprint closes that gap with a sentinel: the rebuild flow writes one extra document, catalog-sentinel, carrying a rebuilt_at epoch timestamp as its final step. Thirty minutes after the rebuild window, io.kestra.plugin.typesense.DocumentGet reads the sentinel back from the same cluster the storefront queries, a Python task compares rebuilt_at against the clock, and a stale or missing sentinel pages Discord and fails the execution.
get_sentinel (io.kestra.plugin.typesense.DocumentGet) fetches document id catalog-sentinel from the products collection and exposes it as the document map output. If the document does not exist, the task fails and the errors block raises the alert, covering the missing case.check_freshness (io.kestra.plugin.scripts.python.Script on the Process task runner) receives the document as JSON through an env variable rendered with {{ outputs.get_sentinel.document | toJson }}, computes the age in hours, and emits stale and age_hours through Kestra's output protocol. The threshold is 26 hours, one nightly cycle plus slack.verdict (io.kestra.plugin.core.flow.If) checks {{ outputs.check_freshness.vars.stale }}. When stale, Discord gets the sentinel age and io.kestra.plugin.core.execution.Fail marks the execution failed, so the missed rebuild surfaces as an incident.log_fresh records the age on healthy runs, building a history of how quickly rebuilds land.Schedule trigger runs at 02:30, 30 minutes after the nightly catalog index blueprint's 02:00 rebuild; align the two crons if you change either.The connection uses the Typesense default port 8108 as a plain value and https: false for a local or private-network cluster; set https: true when your production cluster terminates TLS.
The sentinel pattern needs a writer, a reader on a related schedule, a comparison, and an escalation path. Kestra hosts all four: the rebuild flow writes the sentinel as its last task, this flow reads it back on an offset cron, the Python check runs on the built-in Process runner with no dependencies, and the verdict flows into Discord and execution state. Both flows live side by side in the same namespace with full execution history.
DocumentIndex task with document: {id: catalog-sentinel, rebuilt_at: ...} does it in four lines.products collection schema must include an optional rebuilt_at int64 field; the Quick start adds it.TYPESENSE_HOST: hostname or IP of the Typesense node or load balancer.TYPESENSE_API_KEY: an API key with read access to the collection.DISCORD_WEBHOOK_URL: Discord incoming webhook URL.Add the rebuilt_at field to the collection and write an initial sentinel (adjust host and key):
curl -X PATCH "http://localhost:8108/collections/products" \
-H "X-TYPESENSE-API-KEY: $TYPESENSE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"fields": [{"name": "rebuilt_at", "type": "int64", "optional": true}]}'
curl -X POST "http://localhost:8108/collections/products/documents?action=upsert" \
-H "X-TYPESENSE-API-KEY: $TYPESENSE_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"id\": \"catalog-sentinel\", \"name\": \"catalog sentinel\", \"description\": \"rebuild marker\", \"brand\": \"internal\", \"category\": \"internal\", \"price\": 0.0, \"popularity\": 0.0, \"in_stock\": false, \"rebuilt_at\": $(date +%s)}"
Add the three secrets to your Kestra namespace and execute the flow; the healthy log line reports the sentinel age.
Wait 26 hours or upsert a sentinel with an old rebuilt_at to see the Discord alert and the failed execution.
Add the sentinel upsert as the last task of your rebuild flow and set disabled: false on the after_rebuild trigger.
io.kestra.plugin.typesense.DocumentIndex and rebuilt_at: "{{ execution.startDate | timestamp }}".