Scripted Pipeline and CPS
Scenario: A legacy workflow creates stages dynamically but retains non-serializable objects across durable Pipeline steps.
Pipeline example
node('linux') { try { stage('Test') { sh './test.sh' } } finally { junit 'reports/*.xml' } }
CPS changes ordinary Groovy assumptions
Scripted Pipeline uses node, stage, parallel, try/finally, and general Groovy flow. Jenkins transforms it with continuation-passing style so execution can pause at durable steps and resume after controller restart. State crossing a suspension point must be serializable. Iterators, streams, regex matchers, and Jenkins model objects held across sh, sleep, input, or other steps frequently cause NotSerializableException or unsafe replay behavior.
Keep Groovy as orchestration. Convert data to strings, numbers, lists, and maps before durable steps. NonCPS is appropriate only for pure computation that calls no Pipeline steps and returns serializable values; it is not a universal escape hatch. CPU-heavy Groovy and Jenkins API traversal run on the controller even inside a conceptual build flow, so move real work to agent tools.
Make dynamic execution observable
Generated stages are justified when the input truly arrives at runtime, but deterministic dimensions are clearer as Declarative matrix or named parallel branches. Give branches stable names, cap fan-out, and publish reports in finally. When closures are created in a loop, capture a local value so every branch does not accidentally use the final iteration's variable.
To diagnose resume failure, locate the last durable step, inspect the value retained across it, review plugin changes, and reduce to a minimal example. Test controller restart while sleeping, awaiting input, and running an agent step. A successful Scripted design remains understandable in stage views, survives intended suspension points, and does not turn the controller into an application runtime.
Goal: Practice the concrete behavior in jenkins-labeled-parallel-tests. Learn sections have no Jenkins terminal; the Jenkins lab opens the real shared service in a new full-screen tab inside your private folder.