New to Kestra?
Use blueprints to kickstart your first workflows.
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.
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.
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.
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.findings_alert (io.kestra.plugin.slack.notifications.SlackIncomingWebhook) posts the statement
the gate is about to compile and the current context.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.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.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.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.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.errors alerts Slack when the flow fails, for example when the gateway or the REST API is
unreachable or the statement did not compile.auto_remediate, dry_run false and a human approval.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.
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.
gateway_url, pointed at a running Flink cluster
(execution target remote).rest_url, so the deploy can be verified
against the cluster.catalog.database.table.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.| 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 |
SLACK_WEBHOOK_URL secret.gateway_url and rest_url for your cluster. Set statement to the streaming INSERT you
want to deploy, with fully qualified table names.EXPLAIN and reports whether the statement compiles against
the catalog. Nothing is deployed.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.daily trigger once the inputs match your cluster. It stays in compile check only
mode.job_name_contains so the re-verify matches the exact job the statement starts, when several
jobs run on the cluster.runtime_mode at batch to gate and run a bounded backfill statement, then change the
verify step to assert the job reached FINISHED.