New to Kestra?
Use blueprints to kickstart your first workflows.
Poll an Apache NiFi Process Group's status, alert Slack on backlog or stall, and optionally pause it to stop further growth.
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.
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.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.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.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.log_audit_summary always runs last and logs the final classification.errors block posts to Slack if the flow itself fails outside the gate logic
above.queuedCount and activeThreadCount that triggered
it, never an invented number.GetProcessGroupStatus, StopProcessGroup, and the plugin's JWT-based authentication.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.
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.
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.
| 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 |
NIFI_PASSWORD and SLACK_WEBHOOK
secrets.HEALTHY on a freshly started, empty canvas.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.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.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.io.kestra.plugin.core.flow.Loop
to audit every major sub-flow in a large NiFi canvas from one flow.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.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.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.