GetProcessGroupStatus icon
Return icon
Switch icon
Log icon
SlackIncomingWebhook icon
If icon
StopProcessGroup icon
Fail icon
Schedule icon

NiFi Process Group Backlog and Stall Sentinel

Poll an Apache NiFi Process Group's status, alert Slack on backlog or stall, and optionally pause it to stop further growth.

Categories
Infrastructure

A NiFi Process Group can fill its internal queues for two very different reasons: the pipeline is simply busier than usual, or a downstream processor stopped, errored, or got stuck, and nothing is draining the queue at all. NiFi's own UI shows both as a growing queue count, the difference only becomes obvious once someone opens the canvas and checks whether any threads are actually active. This blueprint polls that distinction directly, alerts Slack with the real numbers that triggered it, and can optionally pause the group so an already-stuck backlog stops growing while a human finds the stuck component.

How it works

  1. probe_process_group_status (io.kestra.plugin.nifi.GetProcessGroupStatus) reads the aggregate queuedCount, queuedBytes, and activeThreadCount for process_group_id, with allowFailure: true so a bad URL or credential does not stop the flow before it can be classified as PROBE_FAILED below.
  2. classify_process_group_status (io.kestra.plugin.core.debug.Return) returns PROBE_FAILED when the probe did not return at all, STALLED when activeThreadCount is 0 while queuedCount is already at or above queued_count_warning_threshold (FlowFiles queued, nothing processing them), BACKLOG_CRITICAL or BACKLOG_WARNING from queuedCount against the two thresholds, HEALTHY otherwise.
  3. route_by_process_group_status (io.kestra.plugin.core.flow.Switch) branches on that status: HEALTHY logs it, the other four each alert Slack with the real queuedCount and activeThreadCount that triggered it, never an invented number. An unexpected value falls through to a defaults branch that logs it rather than being silently dropped.
  4. remediate_gate (io.kestra.plugin.core.flow.If) runs only when the status was STALLED or BACKLOG_CRITICAL, auto_remediate is true, and dry_run is false. It calls io.kestra.plugin.nifi.StopProcessGroup on this one process_group_id, then calls GetProcessGroupStatus again to confirm activeThreadCount actually dropped to 0, failing the flow with io.kestra.plugin.core.execution.Fail if the stop is not confirmed rather than silently reporting success.
  5. log_audit_summary always runs last and logs the final classification.
  6. The errors block posts to Slack if the flow itself fails outside the gate logic above.

What you get

  • A real distinction between "busy" and "stuck", instead of a single queue-depth number that looks the same for both.
  • A Slack alert carrying the exact queuedCount and activeThreadCount that triggered it, never an invented number.
  • An optional, verified pause: stopping a Process Group is confirmed by re-reading its status afterward, a stop that silently failed is never reported as fixed.
  • A fully local test path against the official Apache NiFi Docker image, no NiFi cluster needed.

Who it's for

  • Data engineering and platform teams running Apache NiFi who need to know the moment a dataflow stalls, not just when its queue eventually overflows.
  • Teams evaluating the NiFi plugin who want a working example of GetProcessGroupStatus, StopProcessGroup, and the plugin's JWT-based authentication.

Why orchestrate this with Kestra

NiFi's own UI and REST API expose queuedCount and activeThreadCount, but nothing in NiFi itself alerts on the combination, that logic would otherwise live in a bespoke monitoring script polling the REST API on a timer. Kestra replaces that script with a declarative flow: the schedule, the stall-versus-backlog classification, the Slack alert, and the optional verified pause are all one auditable execution history.

Prerequisites

  • For local testing, the official Apache NiFi Docker image with single-user authentication:

    docker run --name nifi -d -p 8443:8443 \\
      -e SINGLE_USER_CREDENTIALS_USERNAME=admin \\
      -e SINGLE_USER_CREDENTIALS_PASSWORD="<a-password-at-least-12-characters>" \\
      apache/nifi:latest
    

    NiFi's single-user password must be at least 12 characters or the image generates a random one instead and logs it, check the container logs if login fails. The UI and REST API are both served over HTTPS on port 8443 with a self-signed certificate by default, which is why ssl_verify defaults to false here.

  • To see BACKLOG_WARNING/BACKLOG_CRITICAL/STALLED rather than HEALTHY, build a simple flow in the NiFi canvas (for example GenerateFlowFile feeding a processor you then stop) so FlowFiles queue up without draining.

  • For real NiFi, a user with permission to view flow status and, if auto_remediate is used, permission to modify the target Process Group's state.

  • A Slack incoming webhook for alerts.

Secrets

  • NIFI_PASSWORD: password for nifi_username. The plugin's own username property is not a secret field, only password is.

  • SLACK_WEBHOOK: Slack incoming webhook URL used by the alert tasks and the errors block.

    In Kestra OSS, set this as a base64-encoded environment variable, for example SECRET_NIFI_PASSWORD.

Inputs

Input Type Default Allowed values
nifi_url STRING https://localhost:8443 any reachable NiFi base URL
nifi_username STRING admin any NiFi username
ssl_verify BOOL false true, false
process_group_id STRING root a Process Group UUID, or root
queued_count_warning_threshold INT 100 any non-negative integer
queued_count_critical_threshold INT 1000 any non-negative integer, greater than the warning threshold
auto_remediate BOOL false true, false
dry_run BOOL true true, false

Quick start

  1. Start the NiFi container above and add the NIFI_PASSWORD and SLACK_WEBHOOK secrets.
  2. Run this flow manually with the defaults against the root group, it should report HEALTHY on a freshly started, empty canvas.
  3. Build a small flow that queues FlowFiles without draining them, lower queued_count_warning_threshold to match, and run again, it should report BACKLOG_WARNING or STALLED depending on whether you also stopped the downstream processor.
  4. Set auto_remediate: true and dry_run: false and run it again while STALLED or BACKLOG_CRITICAL, it should stop the group and log the verified confirmation.
  5. Enable the every_10_minutes trigger, targeting a specific child Process Group ID rather than root if remediation should not be able to halt the entire canvas.

How to extend

  • Loop this flow over a list of Process Group IDs with io.kestra.plugin.core.flow.Loop to audit every major sub-flow in a large NiFi canvas from one flow.
  • Add queuedBytes to the classification alongside queuedCount, useful when a group's backlog is a small number of very large FlowFiles rather than many small ones.
  • Call io.kestra.plugin.nifi.StartProcessGroup after an operator has fixed the stuck component, as a second, explicitly separate flow run, rather than auto-restarting here.

Pitfalls

  • activeThreadCount is a single instantaneous sample; a healthy, bursty group can briefly read 0 between batches. STALLED only fires when queuedCount is also at or above queued_count_warning_threshold, reducing false positives from a momentary idle gap, but a single poll is still a snapshot, not a trend.
  • queuedCount, queuedBytes, and activeThreadCount come back null, treated here as 0, if NiFi's own response omits those keys, observed for a group with no components at all.
  • StopProcessGroup stops every component in the targeted Process Group, including the entire canvas if process_group_id is root, it does not and cannot restart just the one stuck processor, the plugin has no component-level task. Finding and fixing the actual stuck component still needs a human looking at NiFi's own bulletin board.
  • Stopping a group does not clear its existing queue, FlowFiles already queued stay queued until the group is manually started again after the root cause is fixed.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.