id: horizondb-durable-instance-health-gate
namespace: company.team
description: |
Audit an Azure HorizonDB durable function store for Failed and Running instance counts,
classify the result HEALTHY, WARNING, CRITICAL or PROBE_FAILED, alert Slack with the real
counts, optionally cancel one named stuck instance an operator has already identified, and
log a final audit summary either way.
inputs:
- id: database
type: STRING
displayName: HorizonDB database name
description: Target database on the HorizonDB server. Maps to the ListInstances,
Cancel, and GetStatus tasks' database field.
defaults: "orchestrations"
- id: primary_watch_status
type: SELECT
displayName: Status this gate watches
description: Failed only classifies on the failed instance count, Running only
classifies on the running backlog count, Both classifies on either.
values:
- "Failed"
- "Running"
- "Both"
defaults: "Both"
- id: failed_count_critical_threshold
type: INT
displayName: Failed instance count threshold
description: Number of instances in Failed status at or above which the run is
classified CRITICAL.
defaults: 5
- id: running_backlog_warning_threshold
type: INT
displayName: Running backlog threshold
description: Number of instances still in Running status at or above which the
run is classified WARNING, a sign of a stalled worker pool rather than
normal in-flight work.
defaults: 50
- id: sample_limit
type: INT
displayName: Sample limit per probe
description: Maximum rows pulled per status by each ListInstances call. Maps to
the ListInstances task's limit field, which pg_durable itself caps at
10000.
defaults: 100
- id: use_entra_id
type: BOOL
displayName: Authenticate with Azure Entra ID
description: When true, connects with Entra ID instead of a static password.
Maps to the HorizonDB tasks' useEntraId field.
defaults: false
- id: cancel_instance_id
type: STRING
displayName: Instance ID to cancel
description: Leave empty to never cancel anything. When set, together with
auto_remediate true and dry_run false, cancels exactly this one instance,
the one an operator already identified from a prior alert on this gate,
never a bulk cancel.
defaults: ""
- id: auto_remediate
type: BOOL
displayName: Auto remediate
description: When true, together with dry_run false and cancel_instance_id set,
cancel that one instance and verify the result.
defaults: false
- id: dry_run
type: BOOL
displayName: Dry run
description: Must be false, together with auto_remediate true, for the cancel to
actually run.
defaults: true
tasks:
- id: probe_failed_instances
type: io.kestra.plugin.azure.horizondb.durable.ListInstances
description: Read-only. Counts instances currently in Failed status.
allowFailure: true
host: "{{ secret('HORIZONDB_HOST') }}"
database: "{{ inputs.database }}"
username: "{{ secret('HORIZONDB_USERNAME') }}"
password: "{{ secret('HORIZONDB_PASSWORD') }}"
useEntraId: "{{ inputs.use_entra_id }}"
tenantId: "{{ secret('AZURE_TENANT_ID') }}"
clientId: "{{ secret('AZURE_CLIENT_ID') }}"
clientSecret: "{{ secret('AZURE_CLIENT_SECRET') }}"
statusFilter: "Failed"
limit: "{{ inputs.sample_limit }}"
fetchType: FETCH
- id: probe_running_instances
type: io.kestra.plugin.azure.horizondb.durable.ListInstances
description: Read-only. Counts instances currently in Running status.
allowFailure: true
host: "{{ secret('HORIZONDB_HOST') }}"
database: "{{ inputs.database }}"
username: "{{ secret('HORIZONDB_USERNAME') }}"
password: "{{ secret('HORIZONDB_PASSWORD') }}"
useEntraId: "{{ inputs.use_entra_id }}"
tenantId: "{{ secret('AZURE_TENANT_ID') }}"
clientId: "{{ secret('AZURE_CLIENT_ID') }}"
clientSecret: "{{ secret('AZURE_CLIENT_SECRET') }}"
statusFilter: "Running"
limit: "{{ inputs.sample_limit }}"
fetchType: FETCH
- id: classify_orchestration_health
type: io.kestra.plugin.core.debug.Return
description: PROBE_FAILED when either probe produced no output at all, CRITICAL
when the watched failed count meets its threshold, WARNING when the
watched running backlog meets its threshold, HEALTHY otherwise.
format: "{{ (outputs.probe_failed_instances is not defined or
outputs.probe_running_instances is not defined) ? 'PROBE_FAILED' :
((((inputs.primary_watch_status == 'Failed' or inputs.primary_watch_status
== 'Both') and (outputs.probe_failed_instances.size ?? 0) >=
inputs.failed_count_critical_threshold)) ? 'CRITICAL' :
((((inputs.primary_watch_status == 'Running' or
inputs.primary_watch_status == 'Both') and
(outputs.probe_running_instances.size ?? 0) >=
inputs.running_backlog_warning_threshold)) ? 'WARNING' : 'HEALTHY')) }}"
- id: route_by_orchestration_health
type: io.kestra.plugin.core.flow.Switch
description: Branch A logs a healthy store. Branch B alerts Slack with the real
failed and running counts when either threshold is met, or the probe
itself failed.
value: "{{ outputs.classify_orchestration_health.value }}"
cases:
"HEALTHY":
- id: log_healthy
type: io.kestra.plugin.core.log.Log
message: "HorizonDB {{ inputs.database }} healthy. failed={{
outputs.probe_failed_instances.size }} running={{
outputs.probe_running_instances.size }}."
"WARNING":
- id: alert_warning
type: io.kestra.plugin.slack.notifications.SlackIncomingWebhook
url: "{{ secret('SLACK_WEBHOOK') }}"
payload: |
{{ {"text": "HorizonDB " ~ inputs.database ~ " WARNING. Running backlog at " ~ outputs.probe_running_instances.size ~ " instances, at or above the " ~ inputs.running_backlog_warning_threshold ~ " threshold. Failed count is " ~ outputs.probe_failed_instances.size ~ ". This usually means a stalled worker pool, not a traffic spike."} | toJson }}
"CRITICAL":
- id: alert_critical
type: io.kestra.plugin.slack.notifications.SlackIncomingWebhook
url: "{{ secret('SLACK_WEBHOOK') }}"
payload: |
{{ {"text": "HorizonDB " ~ inputs.database ~ " CRITICAL. " ~ outputs.probe_failed_instances.size ~ " instance(s) in Failed status, at or above the " ~ inputs.failed_count_critical_threshold ~ " threshold. Running backlog is " ~ outputs.probe_running_instances.size ~ ". Query df.list_instances('Failed') directly to find the exact instance IDs."} | toJson }}
"PROBE_FAILED":
- id: alert_probe_failed
type: io.kestra.plugin.slack.notifications.SlackIncomingWebhook
url: "{{ secret('SLACK_WEBHOOK') }}"
payload: |
{{ {"text": "HorizonDB instance audit on database " ~ inputs.database ~ " did not return a result from one or both ListInstances calls. Check HORIZONDB_HOST, credentials, and use_entra_id."} | toJson }}
defaults:
- id: log_unhandled_health_status
type: io.kestra.plugin.core.log.Log
message: "Unhandled HorizonDB health status: {{
outputs.classify_orchestration_health.value }}"
- id: remediate_gate
type: io.kestra.plugin.core.flow.If
description: Runs only when an operator has set cancel_instance_id to a specific
instance from a prior alert on this gate, and auto_remediate is true and
dry_run is false. Never cancels in bulk.
condition: "{{ inputs.cancel_instance_id != '' and inputs.auto_remediate and not
inputs.dry_run }}"
then:
- id: cancel_target_instance
type: io.kestra.plugin.azure.horizondb.durable.Cancel
description: df.cancel() does not document a return value confirming the
instance actually stopped, verify_cancel below checks the real status
afterward.
allowFailure: true
host: "{{ secret('HORIZONDB_HOST') }}"
database: "{{ inputs.database }}"
username: "{{ secret('HORIZONDB_USERNAME') }}"
password: "{{ secret('HORIZONDB_PASSWORD') }}"
useEntraId: "{{ inputs.use_entra_id }}"
tenantId: "{{ secret('AZURE_TENANT_ID') }}"
clientId: "{{ secret('AZURE_CLIENT_ID') }}"
clientSecret: "{{ secret('AZURE_CLIENT_SECRET') }}"
instanceId: "{{ inputs.cancel_instance_id }}"
reason: "Cancelled by horizondb-durable-instance-health-gate after operator
review (execution {{ execution.id }})."
- id: verify_cancel
type: io.kestra.plugin.azure.horizondb.durable.GetStatus
allowFailure: true
host: "{{ secret('HORIZONDB_HOST') }}"
database: "{{ inputs.database }}"
username: "{{ secret('HORIZONDB_USERNAME') }}"
password: "{{ secret('HORIZONDB_PASSWORD') }}"
useEntraId: "{{ inputs.use_entra_id }}"
tenantId: "{{ secret('AZURE_TENANT_ID') }}"
clientId: "{{ secret('AZURE_CLIENT_ID') }}"
clientSecret: "{{ secret('AZURE_CLIENT_SECRET') }}"
instanceId: "{{ inputs.cancel_instance_id }}"
- id: report_cancel_result
type: io.kestra.plugin.core.flow.If
description: Fails the flow when the cancel call or the verification probe did
not come back, or the instance is still Running, so a cancel that did
not take is never silently reported as done.
condition: "{{ outputs.cancel_target_instance is not defined or
outputs.verify_cancel is not defined or outputs.verify_cancel.status
== 'Running' }}"
then:
- id: cancel_not_confirmed
type: io.kestra.plugin.core.execution.Fail
errorMessage: "Cancel of instance {{ inputs.cancel_instance_id }} did not
confirm as stopped (status {{ outputs.verify_cancel.status ??
'unreachable' }})."
else:
- id: cancel_confirmed
type: io.kestra.plugin.core.log.Log
message: "Instance {{ inputs.cancel_instance_id }} cancelled and confirmed.
status={{ outputs.verify_cancel.status }}."
- id: log_audit_summary
type: io.kestra.plugin.core.log.Log
description: Final audit log confirming the gate ran, regardless of the branch
taken above.
message: "HorizonDB durable instance health gate completed. database={{
inputs.database }} status={{ outputs.classify_orchestration_health.value
}} failed={{ outputs.probe_failed_instances.size }} running={{
outputs.probe_running_instances.size }}"
errors:
- id: alert_flow_failure
type: io.kestra.plugin.slack.notifications.SlackIncomingWebhook
url: "{{ secret('SLACK_WEBHOOK') }}"
payload: |
{{ {"text": "HorizonDB durable instance health gate flow failed (execution " ~ execution.id ~ "). Check the execution logs."} | toJson }}
triggers:
- id: hourly
type: io.kestra.plugin.core.trigger.Schedule
description: Shipped disabled, and always in safe mode by default.
cron: "0 * * * *"
disabled: true
inputs:
database: "orchestrations"
primary_watch_status: "Both"
failed_count_critical_threshold: 5
running_backlog_warning_threshold: 50
sample_limit: 100
use_entra_id: false
cancel_instance_id: ""
auto_remediate: false
dry_run: true