New to Kestra?
Use blueprints to kickstart your first workflows.
Find Kafka Connect sinks that skip bad records without a DLQ, provision a retained topic and verify the new config behind approval.
Replacing a connector config restarts its tasks. DLQ records contain the original bytes and error context, which can expose sensitive data. Restrict both DLQ access and Kestra execution access: the saved config can contain credentials.
| Guard | What it stops |
|---|---|
| One exact connector, sink type, errors.tolerance=all and empty DLQ | Changing sources, fail-fast sinks or an existing error-routing policy |
| RUNNING connector with nonempty RUNNING tasks | Restarting an intentional pause or acting on an already failed pipeline |
| Two mode inputs and explicit Pause approval | An audit creating a topic or restarting tasks |
| Full config and status rechecks after approval and before replacement | Overwriting a plan that changed while approval or provisioning waited |
| Reserved topic name, shape and retention checks | Adopting a topic that would immediately expire or compact rejected records |
| Exact config readback, topic existence and task health | Reporting an accepted but ineffective config update as a repair |
read_config (io.kestra.plugin.kafka.ConnectorGetConfig), read_plugins (io.kestra.plugin.core.http.Request), read_status (ConnectorGetStatus) and list_topics (TopicList) audit the selected connector. assess requires a canonical sink class, tolerance all, an empty or whitespace-only DLQ name and running tasks.unprotected_sink posts the gap to Slack. live_mode requires auto_remediate=true and dry_run=false; approve waits for approved=true. Declining ends without a write.fresh_config and fresh_status reject a stale approval. provision_dlq (TopicCreate) creates kestra-dlq-<connector_name> idempotently. inspect_dlq (TopicDescribe) checks one partition, the requested replication factor, delete cleanup, seven-day retention and no byte retention cap. Existing topics are never altered.before_update and before_update_status recheck eligibility. install_dlq (ConnectorUpdateConfig) preserves the current config and adds the topic name, context headers and replication setting. await_tasks polls for up to 12 iterations at five-second intervals. verify_config, verify_topics and verify_result require the exact expected config and a visible topic. Any error alerts Slack.A visible warning for a silent-loss configuration, a dedicated retained DLQ and a verified config change. A failed partial pass leaves its topic available for a reconciled retry.
Platform teams responsible for Kafka Connect sinks where malformed input is tolerated so healthy traffic can continue.
The incident needs an audit, a human decision, broker provisioning and a connector restart across two APIs. Kestra keeps that approval and its snapshot with the execution, queues overlapping runs and alerts when the readback fails.
Kestra 2.0.5, Kafka plugin 1.10.5, Slack plugin 2.1.0 and Confluent Kafka/Connect 7.9.0. FileStream sinks used JsonConverter without schemas. Slack was the existing local HTTP sink.
Before repair, kafka-consumer-groups --describe showed committed offset 5, end offset 5 and lag 0. The sink contained only the two valid records from five inputs; three malformed records had no DLQ. The connector and task stayed RUNNING. After repair, a new valid record reached the sink and a new malformed record appeared once in the DLQ. kafka-console-consumer read its original bytes with topic and offset headers; kafka-get-offsets reported DLQ end offset 1. Previously skipped records were not recovered.
| Case | Execution | Result |
|---|---|---|
| Existing DLQ | Qgc04DHgHKcJCLJZ0Dk9v |
SUCCESS; existing topic and header policy preserved |
| Dry run | 3QgqARsgaNKE1CkmWQB1Xr |
SUCCESS; auto_remediate true, dry_run true, no writes |
| Declined approval | 2X51aYrxoS54uhqGwt5IyV |
SUCCESS; config unchanged |
| Remediation | 6WiyDTd7V6PaNbgjjI6DcH |
SUCCESS; one valid row delivered and one malformed record retained |
| Repeat | 57aAXsFKTk4eHEWU3HS34K |
SUCCESS; no topic or config writes |
| Refused config PUT | 713tfKpHbTUP6VYJ6sEtrW |
FAILED as intended; created topic retained |
| Partial recovery | 4PcFCEGS382zoLkncWKJPQ |
SUCCESS; existing topic reused and delivery proved |
| Config edit during approval | 60nROK53WKdFxJRhwdCzmr |
FAILED as intended; operator edit preserved, no writes |
| Tolerant source | 376y2sbYCwmaoll7gUu9Ra |
SUCCESS; no writes |
| Fail-fast sink | 6dM4xp8qUanBmOHnJrjtV3 |
SUCCESS; no writes |
| Intentional pause | 2E7IWfJmHVhRdw52YbugRY |
SUCCESS; no writes |
| Automation disabled | 6CHKGSAUeC7fXk6qzeg07v |
SUCCESS; dry_run false, auto_remediate false, no writes |
| Whitespace DLQ name | 3DWXtf4LJzTXm2nCGzRF5e |
SUCCESS; treated as missing |
| Wrong-retention lookalike | 2CHP666vpyin8blq66664v |
FAILED as intended; topic and connector untouched |
| Three replicas on one broker | 3UrHGTCStiZrByjrhizZZN |
FAILED as intended; no connector write |
| HTTP 200 without DLQ keys | 2xn6oajzprPvz8XQaJJ8fR |
FAILED as intended; config readback caught the ineffective update |
A second fresh broker/worker pair reproduced the baseline and repeated healthy 4EiF4kgXZkUbFdpiUiql63, remediation 5MmjGFiigKtlZevfo7PXgO, race_or_partial qGOzz1iLo9rQEp5Ruwkzc on the same runtime bytes. The no-effect test forwarded a genuine config PUT with the DLQ keys stripped: Connect returned HTTP 200, then the real config readback failed verification. All readbacks came from the real worker.
Kafka and a Kafka Connect worker on that same cluster, the Kafka plugin and a Slack incoming webhook. Reserve the kestra-dlq- prefix. Connector names must form valid Kafka topic names after the prefix is added. connector.class must use the canonical class name listed by /connector-plugins.
Kestra needs Connect config/status reads, plugin inventory reads and config update permission on the named connector. Its Kafka principal needs Describe, DescribeConfigs and Create for the reserved DLQ names. The worker's principal needs Write and Describe on the DLQ. Configure authentication/TLS properties on all relevant Kafka tasks and credentials on both Connect tasks and the HTTP inventory request for a secured deployment.
KAFKA_CONNECT_URL: worker REST base URL.KAFKA_BOOTSTRAP_SERVERS: brokers used by that worker.SLACK_WEBHOOK_URL: incoming webhook for findings and failures.| Input | Default | Purpose |
|---|---|---|
connect_url |
Secret | Connect REST URL without a trailing slash |
bootstrap_servers |
Secret | Worker cluster's brokers |
connector_name |
Required | One exact connector |
dlq_replication_factor |
3 |
Approved replica policy; 1 only for a single-broker lab |
auto_remediate |
false |
Permit a change to reach approval |
dry_run |
true |
Keep every write disabled |
slack_webhook_url |
Secret | Webhook; permits a local sink for testing |
connector_name and run with the defaults. Check the sink, tolerance, missing-DLQ and running flags in report.auto_remediate=true and dry_run=false, then approve the task restart with approved=true.Change retention only by updating both provision_dlq.configs and check_topic_shape. Existing topics with another policy are refused rather than modified. Add destination-specific canaries before treating this as proof for a different sink implementation.
Limits: one connector per execution. Existing nonempty DLQ names are preserved even when their topics are absent; Connect normally attempts to create a configured missing DLQ itself. This flow prevents future converter-error loss and does not replay skipped records. Concurrency is one for this deployed flow only. Kafka Connect has no conditional config PUT or stable incarnation ID, so coordinate external config writers and connector deletion throughout live runs; the last-read-to-write interval cannot be made atomic here. The flow verifies config, topic policy and reported task health. Canary delivery was proved independently for FileStream/JsonConverter. Authenticated clusters, replica failures, other sinks and real Slack delivery were not exercised.
This blueprint was created by zkasuran.
