New to Kestra?
Use blueprints to kickstart your first workflows.
Monitor expected partner, vendor, and bank files in S3. Alert Slack when a feed is late, missing, empty, or duplicated, and post a daily arrival report.
Diagram unavailable
We could not build the topology for this blueprint. The flow itself is valid, use the YAML on the left to run it.
Almost every company depends on files it does not control: bank statements, payroll exports, vendor price lists, partner order feeds, CRM dumps from another team. When one of them silently does not arrive, nothing fails — the downstream pipeline just loads nothing, and someone notices days later in a dashboard. This blueprint turns "we expect these files every day by these times" into a declarative SLA monitor: you list the feeds, and Kestra tells you once when a feed is missing, empty, or duplicated, tells you again when it recovers, and sends an end-of-day arrival report.
It works with Amazon S3 and any S3-compatible storage (MinIO, Cloudflare R2, Wasabi, Backblaze B2, Ceph) and needs no database, no Lambda, and no changes on the sender's side.
check_every_15_min (Schedule) runs the checks. daily_arrival_report (Schedule, 18:00) runs them with mode: report. on_upload_event (Webhook) lets an S3 event notification or the sender's upload script request an instant check.check_feeds, io.kestra.plugin.core.flow.Loop, 5 in parallel):list_files (io.kestra.plugin.aws.s3.List) lists objects under the feed's prefix matching its pattern. {yyyy}, {MM} and {dd} in the prefix are replaced with today's date in your time zone, so date-partitioned landing folders work out of the box.
evaluate (io.kestra.plugin.core.output.OutputValues) keeps files modified since local midnight and classifies the feed:
| Status | Meaning | Alert |
|---|---|---|
NOT_EXPECTED |
Today is not in the feed's days |
– |
WAITING |
Fewer than min_files, deadline not reached |
– |
MISSING |
Fewer than min_files after the deadline |
:rotating_light: |
TOO_SMALL |
A file is smaller than min_bytes (empty / truncated) |
:warning: |
DUPLICATE |
Two files today share an ETag (same content re-sent) | :warning: |
LATE |
Complete, but the first file arrived after the deadline | recovery only |
ON_TIME |
Complete before the deadline | recovery only |
alert_on_change (If) posts to Slack only when the state changes into a problem state or out of one, so a missing feed produces one alert and one recovery message, not one alert every 15 minutes.
record_state (io.kestra.plugin.core.kv.Set) stores today's state per feed in the KV store (7-day TTL) for de-duplication and reporting.
report mode, slack_report posts one message with every feed's state, file count, first arrival time and deadline.errors branch alerts Slack — a broken monitor is never mistaken for "all files arrived".An S3 event can tell you that a file arrived; it can never tell you that one did not. Detecting absence needs a schedule, a notion of deadlines and delivery days per feed, state to avoid alert storms, and a report — usually spread across cron, a script, and a database. Kestra provides all of it declaratively: schedules and a webhook, a parallel Loop over feeds, the KV store for state, and Slack alerting, in one versioned YAML file. Because each feed is configuration, adding a new partner feed is a one-line change in the feeds input, not new code.
s3:ListBucket on it. No read access to file contents is needed.AWS_ACCESS_KEY_ID: access key allowed to list the inbound bucket(s).AWS_SECRET_ACCESS_KEY: matching secret key.AWS_DEFAULT_REGION: bucket region (e.g. eu-west-1; use us-east-1 or your provider's region for S3-compatible stores).SLACK_WEBHOOK_URL: Slack incoming webhook for alerts and the daily report.feeds (JSON): list of expected feeds. Per feed:name (required): unique identifier, used in alerts and KV keys.prefix (required): key prefix; supports {yyyy}, {MM}, {dd}.pattern (default .*): Java regex matched against the full key.deadline (default 23:59): local HH:mm by which the feed must be complete.min_files (default 1), min_bytes (default 1).days (default every day): e.g. ["MON","TUE","WED","THU","FRI"].bucket (optional): overrides the bucket input.bucket (STRING, default my-inbound-bucket): default inbound bucket.timezone (STRING, default UTC): IANA zone for deadlines, "today" and weekdays.mode (SELECT check | report, default check).feeds with your own, and set bucket and timezone (also set timezone on the daily_arrival_report trigger).WAITING, feeds past their deadline with no files alert MISSING.Add the endpoint to the plugin defaults, for example for MinIO:
pluginDefaults:
- type: io.kestra.plugin.aws
values:
endpointOverride: https://minio.example.com
compatibilityMode: true
forcePathStyle: true
LastModified in your time zone. Prefixes that hold years of history are listed in full — prefer date-partitioned prefixes ({yyyy}/{MM}/{dd}) or move processed files away.list_files returns at most 1,000 objects per feed (maxFiles).days are English three-letter abbreviations.outputs.evaluate.values.evaluation (per iteration): JSON such as {"name": "bank_statements", "status": "LATE", "files": 1, "first_arrival": "07:42", "deadline": "07:00", ...}.file_sla_<feed>_<yyyy-MM-dd> holding the same JSON.ON_TIME or LATE with a Subflow task in alert_on_change.channel or webhook field to each feed.MISSING.