2424import org .apache .flink .kubernetes .operator .api .bluegreen .DeploymentType ;
2525import org .apache .flink .kubernetes .operator .api .status .FlinkBlueGreenDeploymentState ;
2626import org .apache .flink .kubernetes .operator .api .status .Savepoint ;
27+ import org .apache .flink .kubernetes .operator .api .status .SavepointFormatType ;
28+ import org .apache .flink .kubernetes .operator .api .status .SnapshotTriggerType ;
29+ import org .apache .flink .kubernetes .operator .config .KubernetesOperatorConfigOptions ;
2730import org .apache .flink .kubernetes .operator .controller .FlinkBlueGreenDeployments ;
2831import org .apache .flink .kubernetes .operator .controller .FlinkResourceContext ;
2932import org .apache .flink .kubernetes .operator .utils .bluegreen .BlueGreenSpecUtils ;
3235
3336import io .fabric8 .kubernetes .api .model .ObjectMeta ;
3437import io .javaoperatorsdk .operator .api .reconciler .UpdateControl ;
38+ import lombok .AllArgsConstructor ;
39+ import lombok .Getter ;
3540import org .slf4j .Logger ;
3641import org .slf4j .LoggerFactory ;
3742
4247import static org .apache .flink .kubernetes .operator .controller .bluegreen .BlueGreenKubernetesService .isFlinkDeploymentReady ;
4348import static org .apache .flink .kubernetes .operator .controller .bluegreen .BlueGreenKubernetesService .suspendFlinkDeployment ;
4449import static org .apache .flink .kubernetes .operator .controller .bluegreen .BlueGreenKubernetesService .updateFlinkDeployment ;
45- import static org .apache .flink .kubernetes .operator .utils .bluegreen .BlueGreenSpecUtils .configureSavepoint ;
50+ import static org .apache .flink .kubernetes .operator .utils .bluegreen .BlueGreenSpecUtils .fetchSavepointInfo ;
51+ import static org .apache .flink .kubernetes .operator .utils .bluegreen .BlueGreenSpecUtils .getLastCheckpoint ;
52+ import static org .apache .flink .kubernetes .operator .utils .bluegreen .BlueGreenSpecUtils .isSavepointRequired ;
53+ import static org .apache .flink .kubernetes .operator .utils .bluegreen .BlueGreenSpecUtils .lookForCheckpoint ;
4654import static org .apache .flink .kubernetes .operator .utils .bluegreen .BlueGreenSpecUtils .prepareFlinkDeployment ;
55+ import static org .apache .flink .kubernetes .operator .utils .bluegreen .BlueGreenSpecUtils .triggerSavepoint ;
56+ import static org .apache .flink .kubernetes .operator .utils .bluegreen .BlueGreenUtils .getReconciliationReschedInterval ;
4757import static org .apache .flink .kubernetes .operator .utils .bluegreen .BlueGreenUtils .instantStrToMillis ;
4858import static org .apache .flink .kubernetes .operator .utils .bluegreen .BlueGreenUtils .millisToInstantStr ;
4959
@@ -90,7 +100,7 @@ public UpdateControl<FlinkBlueGreenDeployment> initiateDeployment(
90100 }
91101
92102 /**
93- * Checks if a deployment can be initiated and initiates it if conditions are met.
103+ * Checks if a full transition can be initiated and initiates it if conditions are met.
94104 *
95105 * @param context the transition context
96106 * @param currentDeploymentType the current deployment type
@@ -101,19 +111,28 @@ public UpdateControl<FlinkBlueGreenDeployment> checkAndInitiateDeployment(
101111 BlueGreenDiffType specDiff = BlueGreenSpecUtils .getSpecDiff (context );
102112
103113 if (specDiff != BlueGreenDiffType .IGNORE ) {
104- BlueGreenSpecUtils .setLastReconciledSpec (context );
105-
106114 FlinkDeployment currentFlinkDeployment =
107115 context .getDeploymentByType (currentDeploymentType );
108116
109117 if (isFlinkDeploymentReady (currentFlinkDeployment )) {
110118 if (specDiff == BlueGreenDiffType .TRANSITION ) {
119+ if (handleSavepoint (context , currentFlinkDeployment )) {
120+ // This is the only portion where the last reconciled spec is not set,
121+ // so we can process TRANSITION after the savepoint is done
122+ var savepointingState = calculateSavepointingState (currentDeploymentType );
123+ return patchStatusUpdateControl (context , savepointingState , null )
124+ .rescheduleAfter (getReconciliationReschedInterval (context ));
125+ }
126+
127+ BlueGreenSpecUtils .setLastReconciledSpec (context );
111128 return startTransition (context , currentDeploymentType , currentFlinkDeployment );
112129 } else {
130+ BlueGreenSpecUtils .setLastReconciledSpec (context );
113131 return patchFlinkDeployment (context , currentDeploymentType , specDiff );
114132 }
115133 } else {
116134 if (context .getDeploymentStatus ().getJobStatus ().getState () != JobStatus .FAILING ) {
135+ BlueGreenSpecUtils .setLastReconciledSpec (context );
117136 return patchStatusUpdateControl (context , null , JobStatus .FAILING );
118137 }
119138 }
@@ -150,11 +169,7 @@ private UpdateControl<FlinkBlueGreenDeployment> startTransition(
150169 FlinkDeployment currentFlinkDeployment ) {
151170 DeploymentTransition transition = calculateTransition (currentDeploymentType );
152171
153- FlinkResourceContext <FlinkDeployment > resourceContext =
154- context .getCtxFactory ()
155- .getResourceContext (currentFlinkDeployment , context .getJosdkContext ());
156-
157- Savepoint lastCheckpoint = configureSavepoint (resourceContext );
172+ Savepoint lastCheckpoint = configureInitialSavepoint (context , currentFlinkDeployment );
158173
159174 return initiateDeployment (
160175 context ,
@@ -182,6 +197,85 @@ private FlinkBlueGreenDeploymentState calculatePatchingState(DeploymentType curr
182197 }
183198 }
184199
200+ // ==================== Savepointing Methods ====================
201+
202+ public boolean monitorSavepoint (
203+ BlueGreenContext context , DeploymentType currentDeploymentType ) {
204+
205+ FlinkResourceContext <FlinkDeployment > ctx =
206+ context .getCtxFactory ().getResourceContext (
207+ context .getDeploymentByType (currentDeploymentType ),
208+ context .getJosdkContext ());
209+
210+ String savepointTriggerId = context .getDeploymentStatus ().getSavepointTriggerId ();
211+ var savepointFetchResult = fetchSavepointInfo (ctx , savepointTriggerId );
212+
213+ return !savepointFetchResult .isPending ();
214+ }
215+
216+ private Savepoint configureInitialSavepoint (
217+ BlueGreenContext context ,
218+ FlinkDeployment currentFlinkDeployment ) {
219+
220+ FlinkResourceContext <FlinkDeployment > ctx =
221+ context .getCtxFactory ()
222+ .getResourceContext (currentFlinkDeployment , context .getJosdkContext ());
223+
224+ // If a savepoint is required we fetch it, should be ready by this point
225+ if (isSavepointRequired (context )) {
226+ String savepointTriggerId = context .getDeploymentStatus ().getSavepointTriggerId ();
227+ var savepointFetchResult = fetchSavepointInfo (ctx , savepointTriggerId );
228+
229+ org .apache .flink .core .execution .SavepointFormatType coreSavepointFormatType =
230+ ctx .getObserveConfig ().get (KubernetesOperatorConfigOptions .OPERATOR_SAVEPOINT_FORMAT_TYPE );
231+
232+ var savepointFormatType = SavepointFormatType .valueOf (coreSavepointFormatType .toString ());
233+
234+ return Savepoint .of (savepointFetchResult .getLocation (), SnapshotTriggerType .MANUAL , savepointFormatType );
235+ }
236+
237+ // Else we start looking for the last checkpoint if needed
238+
239+ if (!lookForCheckpoint (context )) {
240+ return null ;
241+ }
242+
243+ return getLastCheckpoint (ctx );
244+ }
245+
246+ private boolean handleSavepoint (
247+ BlueGreenContext context ,
248+ FlinkDeployment currentFlinkDeployment ) {
249+
250+ if (!isSavepointRequired (context )) {
251+ return false ;
252+ }
253+
254+ FlinkResourceContext <FlinkDeployment > ctx =
255+ context .getCtxFactory ()
256+ .getResourceContext (currentFlinkDeployment , context .getJosdkContext ());
257+
258+ String savepointTriggerId = context .getDeploymentStatus ().getSavepointTriggerId ();
259+
260+ if (savepointTriggerId == null || savepointTriggerId .isEmpty ()) {
261+ String triggerId = triggerSavepoint (ctx );
262+ LOG .info ("Savepoint requested (triggerId: {}" , triggerId );
263+ context .getDeploymentStatus ().setSavepointTriggerId (triggerId );
264+ return true ;
265+ }
266+
267+ LOG .debug ("Savepoint previously requested (triggerId: {})" , savepointTriggerId );
268+ return false ;
269+ }
270+
271+ private FlinkBlueGreenDeploymentState calculateSavepointingState (DeploymentType currentType ) {
272+ if (DeploymentType .BLUE == currentType ) {
273+ return FlinkBlueGreenDeploymentState .SAVEPOINTING_BLUE ;
274+ } else {
275+ return FlinkBlueGreenDeploymentState .SAVEPOINTING_GREEN ;
276+ }
277+ }
278+
185279 // ==================== Transition Monitoring Methods ====================
186280
187281 /**
@@ -396,6 +490,7 @@ public UpdateControl<FlinkBlueGreenDeployment> finalizeBlueGreenDeployment(
396490
397491 context .getDeploymentStatus ().setDeploymentReadyTimestamp (millisToInstantStr (0 ));
398492 context .getDeploymentStatus ().setAbortTimestamp (millisToInstantStr (0 ));
493+ context .getDeploymentStatus ().setSavepointTriggerId (null );
399494
400495 return patchStatusUpdateControl (context , nextState , JobStatus .RUNNING );
401496 }
@@ -423,31 +518,20 @@ public static UpdateControl<FlinkBlueGreenDeployment> patchStatusUpdateControl(
423518 return UpdateControl .patchStatus (flinkBlueGreenDeployment );
424519 }
425520
426- // ==================== Inner Classes ====================
521+ // ==================== DTO/Result Classes ====================
427522
523+ @ Getter
524+ @ AllArgsConstructor
428525 private static class DeploymentTransition {
429526 final DeploymentType nextDeploymentType ;
430527 final FlinkBlueGreenDeploymentState nextState ;
431-
432- DeploymentTransition (
433- DeploymentType nextDeploymentType , FlinkBlueGreenDeploymentState nextState ) {
434- this .nextDeploymentType = nextDeploymentType ;
435- this .nextState = nextState ;
436- }
437528 }
438529
530+ @ Getter
531+ @ AllArgsConstructor
439532 private static class TransitionState {
440533 final FlinkDeployment currentDeployment ;
441534 final FlinkDeployment nextDeployment ;
442535 final FlinkBlueGreenDeploymentState nextState ;
443-
444- TransitionState (
445- FlinkDeployment currentDeployment ,
446- FlinkDeployment nextDeployment ,
447- FlinkBlueGreenDeploymentState nextState ) {
448- this .currentDeployment = currentDeployment ;
449- this .nextDeployment = nextDeployment ;
450- this .nextState = nextState ;
451- }
452536 }
453537}
0 commit comments