Request icon
OutputValues icon
SlackIncomingWebhook icon
SubmitSql icon
Log icon
If icon
Fail icon
Pause icon
Sleep icon
Schedule icon

Flink SQL Pipeline Deploy Gate

Compile check a Flink SQL statement with EXPLAIN on the SQL Gateway, deploy it behind an approval, then confirm over REST that the job is running.

Categories
DataInfrastructure

A Flink SQL streaming pipeline is deployed as a statement that the SQL Gateway runs against a catalog of source and sink tables. The risk at deploy time is a statement that does not match the catalog it will run against: a renamed column, a dropped table, a type that no longer lines up. The gateway only finds that out when the statement is submitted. By then a broken job may already be running or a good one may have been replaced.

This blueprint puts a compile check in front of the deploy. It runs EXPLAIN PLAN FOR the statement through the io.kestra.plugin.flink.SubmitSql task, which compiles the statement against the live catalog on the SQL Gateway and deploys nothing. A statement that does not resolve comes back as an error and the run stops before any deploy. In remediate mode, after a human approves, the same statement is submitted to start the job, then the Flink REST API is read again to confirm a job that was not running before is running now. A deploy that compiles but does not leave a running job fails the run.

This blueprint was created by zkasuran.

Safety

The deploy starts a long running streaming job that writes to a sink, so it runs only when auto_remediate is true and dry_run is false, then only after a human approves the approve_deploy pause. The default inputs and the schedule leave the flow in compile check only mode. The compile check itself is read only: EXPLAIN compiles the statement and never executes it.

How it works

  1. detect (io.kestra.plugin.core.http.Request) reads GET /jobs/overview from the Flink REST API. baseline (io.kestra.plugin.core.output.OutputValues) keeps the ids of the jobs that are already running, so a job started by this run can be told apart later.
  2. findings_alert (io.kestra.plugin.slack.notifications.SlackIncomingWebhook) posts the statement the gate is about to compile and the current context.
  3. compat_gate (io.kestra.plugin.flink.SubmitSql) runs EXPLAIN PLAN FOR the statement on the SQL Gateway. acceptableStates is FINISHED and ERROR, so a statement that does not compile comes back as a status rather than throwing. gate_eval reads the status and gate_log reports it.
  4. incompatible_guard (io.kestra.plugin.core.flow.If) fails the run through io.kestra.plugin.core.execution.Fail when the status is not FINISHED, so an incompatible statement can never reach the deploy.
  5. apply_gate (io.kestra.plugin.core.flow.If) runs the deploy only when auto_remediate is true and dry_run is false. approve_deploy (io.kestra.plugin.core.flow.Pause) holds for a human.
  6. On approval, submit (io.kestra.plugin.flink.SubmitSql) runs the statement, which starts the job on the cluster. settle (io.kestra.plugin.core.flow.Sleep) waits, then reverify reads GET /jobs/overview again.
  7. verdict (io.kestra.plugin.core.output.OutputValues) checks the submit status and that a job which was not running at baseline is running now, with an optional name filter. verify (io.kestra.plugin.core.flow.If) fails the run through io.kestra.plugin.core.execution.Fail unless the deploy left a running job. On success deployed_alert posts to Slack and deployed_log records the new job ids.
  8. errors alerts Slack when the flow fails, for example when the gateway or the REST API is unreachable or the statement did not compile.

What you get

  • A compile check that resolves a streaming statement against the live catalog before any deploy, so a renamed column or a missing table is caught as an error instead of a broken job.
  • A deploy that runs only behind auto_remediate, dry_run false and a human approval.
  • A re-verify that reads the Flink REST API after the deploy and fails the run unless a job that was not running before is running now. A statement that compiles but does not start a job does not pass.
  • A Slack alert on the statement under test, on a successful deploy and on any failure.

Who it's for

  • Teams that deploy Flink SQL streaming jobs through the SQL Gateway and want a compile check in the pipeline instead of finding a catalog mismatch at submit time.
  • Platform engineers who want the deploy gated behind an approval and verified against the cluster, not assumed from a successful submit call.
  • Anyone promoting a Flink SQL change between environments who wants proof the statement matches the target catalog first.

Why orchestrate this with Kestra

A safe Flink SQL deploy is a compile check, an approval, a submit and a read back of the cluster, in that order. Kestra runs the EXPLAIN compile check, stops the run before the deploy when it fails, holds the approval pause, submits the statement through the typed io.kestra.plugin.flink.SubmitSql task, then compares the running jobs before and after to decide whether the run passes. The Slack alerts and the execution history show every gate and the job it started.

Tested end to end

On Kestra 2.0.5 OSS against a real Flink 1.20.5 SQL Gateway on port 8083 with the Flink JobManager REST API on port 8081. The cluster was a standalone session cluster (one JobManager plus one TaskManager) on the same Docker network. A local HTTP sink stood in for Slack. The source and sink were tables in a Paimon catalog on a file warehouse, registered through a file catalog store so every new gateway session resolves the same catalog. The gated statement was INSERT INTO pm.demo.sink SELECT id, amount, ts FROM pm.demo.src. Every number below was read from the Flink REST API /jobs/overview directly, not only from Kestra's log.

Run Inputs Result
compile check, compatible dry_run true execution 1vo8JjiYxe9NGKVOCfkr5F succeeded. EXPLAIN returned FINISHED. Nothing was deployed
compile check, incompatible dry_run true, statement with a missing column execution 4IsnysyYLlXjcT0mhX47ZE failed at the compile gate. EXPLAIN returned ERROR. The run stopped before the deploy. Slack was alerted
deploy, streaming auto_remediate true, dry_run false, approved execution 3qEKrQSeXa29bNGajPlzb succeeded. Submit status RUNNING. Running jobs went from 0 to 1. The new job 2120930c31ebf12d570b00d08af780c8 was confirmed RUNNING by the REST API
deploy, does not reach running runtime_mode batch, approved execution 11CovaUGfxUeewBZe7Vj8P failed. The bounded job finished, so 0 jobs were running at the re-verify. The verify failed and Slack was alerted
REST API unreachable rest_url at a host that does not resolve execution 2IsbOxKcvdWhomzzbFGqJC failed at detect. Slack was alerted

The running job count before the deploy was 0 while after the streaming deploy it was 1, with the new job confirmed RUNNING by the REST API. The compile gate passed the compatible statement as FINISHED while it caught a missing column as ERROR and stopped the run before any deploy. A batch deploy left no running job, so the verify failed. Those two failures are how the gate proves it can fail rather than passing everything.

Prerequisites

  • A Flink SQL Gateway reachable from Kestra at gateway_url, pointed at a running Flink cluster (execution target remote).
  • The Flink JobManager REST API reachable from Kestra at rest_url, so the deploy can be verified against the cluster.
  • A catalog on the gateway that holds the source and sink tables the statement names. A catalog store makes a persistent catalog visible to every new gateway session, which is what lets the compile check and the deploy resolve the same tables. The statement should use fully qualified names such as catalog.database.table.

Secrets

  • SLACK_WEBHOOK_URL: used by findings_alert, deployed_alert and the errors block. In Kestra OSS, provide it as the base64 encoded environment variable SECRET_SLACK_WEBHOOK_URL.

Inputs

Input Default Purpose
gateway_url http://flink-sql-gateway:8083 Flink SQL Gateway base URL for the compile check and the deploy
rest_url http://flink-jobmanager:8081 Flink JobManager REST base URL for the re-verify
statement example INSERT The streaming INSERT to gate and deploy, fully qualified, no trailing semicolon
runtime_mode streaming streaming keeps the job running, batch runs a bounded job that finishes
job_name_contains empty Optional substring the deployed job name must contain in the re-verify
settle_seconds 8 Wait after the deploy before reading the REST API
statement_timeout 120 Timeout for the EXPLAIN or the INSERT on the gateway
auto_remediate false Must be true before a deploy
dry_run true Must be false before a deploy

Quick start

  1. Add the SLACK_WEBHOOK_URL secret.
  2. Set gateway_url and rest_url for your cluster. Set statement to the streaming INSERT you want to deploy, with fully qualified table names.
  3. Run with the defaults. The flow runs EXPLAIN and reports whether the statement compiles against the catalog. Nothing is deployed.
  4. To deploy, set auto_remediate to true and dry_run to false, run it and approve the paused execution. The flow submits the statement, then reads the REST API and fails if the job is not running.
  5. Enable the daily trigger once the inputs match your cluster. It stays in compile check only mode.

How to extend

  • Set job_name_contains so the re-verify matches the exact job the statement starts, when several jobs run on the cluster.
  • Run the gate once per statement in a larger flow to deploy a set of pipelines, each behind its own compile check.
  • Add a step that cancels the previous version of the job through the Flink REST API before the deploy, for a blue green style replace.
  • Point runtime_mode at batch to gate and run a bounded backfill statement, then change the verify step to assert the job reached FINISHED.
  • Store the approved statement and its execution id in a KV pair for an audit trail of what was deployed and when.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.