New to Kestra?
Use blueprints to kickstart your first workflows.
Detect Db2 packages marked invalid or inoperative in SYSCAT.PACKAGES, rebind an allowlisted batch behind an approval, fail the run if it did not land.
| Finding | What it means | What the flow does |
|---|---|---|
VALID = 'N' (invalid) |
DDL removed something the access plan used, an index or a table or a privilege. Db2 recompiles on first use, so the cost lands on whichever request gets there first | Reports it. Rebinds it when the allowlist covers it, the ceiling allows it, the approval is given |
VALID = 'X' (inoperative) |
A dependency is gone outright. Db2 refuses to run the package at all until somebody rebinds it | Same path. A rebind only succeeds once the missing object is back, which is why the re-read has to fail the run |
| No routine behind the package | It was bound from a bind file by an application. SYSPROC.ADMIN_CMD rejects the CLP REBIND, so there is no SQL route |
Reports it, counts it, never touches it. Names the CLP command to run |
| Held by the allowlist | The package is rebindable but no pattern matched | Reports it as held. Nothing happens until a pattern covers it |
| Past the ceiling | More eligible packages than max_rebinds |
Reports them as deferred. The next run picks them up |
A rebind is not free. It recompiles the statement against current statistics, so a package that was
performing acceptably on an old plan can come back on a different plan that is slower. That is a
performance risk, not a data risk, but it is real on a busy system. Three things keep it bounded.
APREUSE YES asks Db2 to reuse the existing plan wherever it still can. RESOLVE CONSERVATIVE
resolves names only against objects that existed at the original bind. max_rebinds keeps one run
to a batch you can watch.
Nothing is eligible by default. routine_allowlist starts empty, so a first run always reports.
One state this guard cannot fix. If the migration dropped an object outright rather than replacing
it, the routine itself goes invalid as well as its package, so
SYSPROC.REBIND_ROUTINE_PACKAGE answers SQL0443N with reason -2453 instead of rebinding.
Recreate the missing object, then run this flow. The run fails loudly in that case rather than
reporting a fix it did not make.
detect (io.kestra.plugin.jdbc.db2.Query) reads every package in the schema whose
SYSCAT.PACKAGES.VALID is not Y. It joins SYSCAT.ROUTINEDEP on BTYPE = 'K' to
SYSCAT.ROUTINES to find the routine that owns each package, because the package name of an SQL
routine is generated and tells you nothing. It lists the objects still recorded in
SYSCAT.PACKAGEDEP, applies the allowlist with SQL LIKE, numbers the eligible rows so the
ceiling can cut the batch. Read-only.plan (io.kestra.plugin.core.output.OutputValues) turns the rows into the batch the loop will
walk, the name list the re-read will query, one counts line. Gate flags are strings.summary (io.kestra.plugin.core.log.Log) prints the counts with every package named.route (io.kestra.plugin.core.flow.If) stops here when the catalog is clean.alert posts the counts to Slack. no_route_note warns about application packages that need
the CLP.remediate_gate requires auto_remediate true, dry_run false, a non-empty batch.approval (io.kestra.plugin.core.flow.Pause) holds the run. The resume form names the exact
packages with the options they will get.rebind (io.kestra.plugin.core.flow.Loop, concurrencyLimit: 1) calls
SYSPROC.REBIND_ROUTINE_PACKAGE once per package. One at a time, because concurrent rebinds
race on the same catalog rows.verify reads SYSCAT.PACKAGES again for exactly the targeted names. verify_gate fails the
run through io.kestra.plugin.core.execution.Fail if any of them is still not Y.errors posts to Slack with the execution id.A per-schema answer to the question a migration leaves behind: which compiled access plans did my DDL break. The counts line splits the findings into rebindable, held by the allowlist, deferred by the ceiling, no SQL route at all. The rebind runs only for packages you named, in a batch you capped, after you approved it. The catalog read afterwards is what decides success, so a rebind that reported fine but changed nothing fails the run instead of passing quietly.
Db2 LUW DBAs, platform teams that run migrations against Db2, anyone who has watched an application throw a runtime error the morning after a schema change. Also useful as the last step of a migration pipeline: run it with the allowlist set to the schema you just changed.
The work is a catalog read, a conditional write, a second read that has to be able to fail the run. Kestra gives the approval gate, the per-run ceiling, the loop that rebinds one package at a time, the Slack path on failure, without a script holding state. The read-only default plus the Pause means the same flow is safe to schedule for reporting and ready to remediate when somebody is watching.
Run against Db2 12.1.5.0 on Kestra 2.0.5. The degraded state was built from a 5000 row table with
a unique index plus current statistics, so the compiled plan records that index every time. Four
SQL procedures, one SQL function, one static package bound with db2 prep plus db2 bind sat on
top of it. Dropping the index flipped VALID from Y to N in SYSCAT.PACKAGES for every
dependent package while a control package reading another table stayed Y, checked with
db2 "SELECT PKGSCHEMA, PKGNAME, VALID, LAST_BIND_TIME FROM SYSCAT.PACKAGES" before and after.
Detection returned zero findings against the clean catalog, then four against the broken one on the
same inputs. A dry_run=true run named the batch with LAST_BIND_TIME unmoved. An approved run
rebound the allowlisted batch, the re-read showed VALID=Y with LAST_BIND_TIME moved, the
control untouched. A ceiling of 1 against 2 eligible packages rebound exactly one. A declined
approval changed nothing. A detect-only account made the rebind raise SQL0443N reason -551,
failing the run. A DROP INDEX landing while a 15 package batch was running made the loop report
success for all 15 while 11 read back N, which failed the run on the re-read.
Two Db2 behaviours worth knowing before you schedule this. With AUTO_REVAL set to DEFERRED, the
default for a database created on 9.7 or later, Db2 revalidates invalid objects itself when a new
connection comes in, so the N window can close before you look. This guard earns its keep on
AUTO_REVAL = DISABLED databases, on inoperative packages whose dependency is still missing, on
application packages, which Db2 never revalidates at connect. Check with
db2 get db cfg for <db> | grep AUTO_REVAL.
| Secret | Used for |
|---|---|
DB2_PASSWORD |
Default for the jdbc_password input |
SLACK_WEBHOOK_URL |
The alert plus the errors block |
| Input | Type | Default | Notes |
|---|---|---|---|
jdbc_url |
STRING | jdbc:db2://localhost:50000/testdb |
Db2 JDBC URL |
jdbc_username |
STRING | db2inst1 |
SELECT on the catalog views to detect, ALTERIN or BINDADD to rebind |
jdbc_password |
STRING | {{ secret('DB2_PASSWORD') }} |
Never a literal |
package_schema |
STRING | DB2INST1 |
PKGSCHEMA to scan, folded to upper case |
routine_allowlist |
STRING | empty | Comma separated SQL LIKE patterns against the owning routine. Empty means nothing is eligible |
max_rebinds |
INT | 5 |
Per-run ceiling. Eligible packages past it are reported as deferred |
rebind_options |
SELECT | APREUSE YES RESOLVE ANY |
Options string for SYSPROC.REBIND_ROUTINE_PACKAGE |
auto_remediate |
BOOL | false |
Must be true before a rebind is proposed |
dry_run |
BOOL | true |
True reports the batch, changes nothing |
The detecting account needs SELECT on SYSCAT.PACKAGES, SYSCAT.PACKAGEDEP,
SYSCAT.ROUTINEDEP, SYSCAT.ROUTINES, which Db2 grants to PUBLIC by default. Rebinding needs
ALTERIN on the package schema or BINDADD, plus EXECUTE on
SYSPROC.REBIND_ROUTINE_PACKAGE. Point the flow at a detect-only account to keep the guard a
reporter.
DB2_PASSWORD plus SLACK_WEBHOOK_URL as Kestra secrets.routine_allowlist to the schema or prefix your migration touched, for example
PAYMENTS.%. Run again with dry_run=true to see the batch.auto_remediate=true with dry_run=false, run it, read the batch on the
Pause form, resume with approved=true. The re-read fails the run if a package is still not
valid.daily_scan once you trust the reporting. Its inputs force dry_run=true with
auto_remediate=false.routine_allowlist set to the schema you changed,
so the rebind happens while somebody is still watching the deploy.RUNSTATS step before the rebind when the migration changed data volume, so the new plan
is built on current statistics rather than stale ones.SYSCAT.PACKAGEDEP with BTYPE = 'F' to catch packages that depend on a
user defined function, the usual way a package goes inoperative instead of invalid.core.flow.Sleep plus a stricter ceiling on a database where nobody is on
call at migration time.This blueprint was created by zkasuran.
