|
21 | 21 | import org.apache.streampark.console.SpringUnitTestBase; |
22 | 22 | import org.apache.streampark.console.core.entity.FlinkApplication; |
23 | 23 | import org.apache.streampark.console.core.entity.YarnQueue; |
| 24 | +import org.apache.streampark.console.core.enums.FlinkAppStateEnum; |
| 25 | +import org.apache.streampark.console.core.enums.OptionStateEnum; |
24 | 26 | import org.apache.streampark.console.core.service.application.FlinkApplicationActionService; |
25 | 27 | import org.apache.streampark.console.core.service.application.FlinkApplicationManageService; |
26 | 28 | import org.apache.streampark.console.core.service.application.impl.FlinkApplicationManageServiceImpl; |
@@ -146,4 +148,198 @@ void testCheckQueueValidationIfNeeded() { |
146 | 148 | app2.setYarnQueue(nonExistedQueue); |
147 | 149 | assertThat(applicationServiceImpl.validateQueueIfNeeded(app1, app2)).isFalse(); |
148 | 150 | } |
| 151 | + |
| 152 | + @Test |
| 153 | + void testPersistMetricsPreservesInFlightCancellation() { |
| 154 | + assertNonTerminalMetricsPreserveOperation(OptionStateEnum.CANCELLING); |
| 155 | + assertNonTerminalMetricsPreserveOperation(OptionStateEnum.SAVEPOINTING); |
| 156 | + } |
| 157 | + |
| 158 | + @Test |
| 159 | + void testPersistMetricsRecoversInterruptedCancellation() { |
| 160 | + assertInterruptedCancellationRecovers(FlinkAppStateEnum.RUNNING); |
| 161 | + assertInterruptedCancellationRecovers(FlinkAppStateEnum.FAILING); |
| 162 | + } |
| 163 | + |
| 164 | + @Test |
| 165 | + void testPersistMetricsUpdatesUnprotectedNonTerminalState() { |
| 166 | + FlinkApplication persisted = createApplication( |
| 167 | + FlinkAppStateEnum.RUNNING, OptionStateEnum.NONE); |
| 168 | + |
| 169 | + FlinkApplication snapshot = new FlinkApplication(); |
| 170 | + snapshot.setId(persisted.getId()); |
| 171 | + snapshot.setState(FlinkAppStateEnum.FAILING.getValue()); |
| 172 | + snapshot.setOptionState(OptionStateEnum.NONE.getValue()); |
| 173 | + applicationManageService.persistMetrics(snapshot); |
| 174 | + |
| 175 | + FlinkApplication actual = applicationManageService.getById(persisted.getId()); |
| 176 | + assertThat(actual.getState()).isEqualTo(FlinkAppStateEnum.FAILING.getValue()); |
| 177 | + assertThat(actual.getOptionState()).isEqualTo(OptionStateEnum.NONE.getValue()); |
| 178 | + } |
| 179 | + |
| 180 | + @Test |
| 181 | + void testPersistMetricsDoesNotBlockStandaloneSavepointCompletion() { |
| 182 | + FlinkApplication persisted = createApplication( |
| 183 | + FlinkAppStateEnum.RUNNING, OptionStateEnum.SAVEPOINTING); |
| 184 | + |
| 185 | + FlinkApplication completedSnapshot = new FlinkApplication(); |
| 186 | + completedSnapshot.setId(persisted.getId()); |
| 187 | + completedSnapshot.setState(FlinkAppStateEnum.RUNNING.getValue()); |
| 188 | + completedSnapshot.setOptionState(OptionStateEnum.NONE.getValue()); |
| 189 | + applicationManageService.persistMetrics(completedSnapshot); |
| 190 | + |
| 191 | + FlinkApplication actual = applicationManageService.getById(persisted.getId()); |
| 192 | + assertThat(actual.getState()).isEqualTo(FlinkAppStateEnum.RUNNING.getValue()); |
| 193 | + assertThat(actual.getOptionState()).isEqualTo(OptionStateEnum.NONE.getValue()); |
| 194 | + } |
| 195 | + |
| 196 | + @Test |
| 197 | + void testPersistMetricsConvergesCancellationOnTerminalState() { |
| 198 | + FlinkApplication persisted = createApplication( |
| 199 | + FlinkAppStateEnum.CANCELLING, OptionStateEnum.CANCELLING); |
| 200 | + |
| 201 | + FlinkApplication terminalSnapshot = new FlinkApplication(); |
| 202 | + terminalSnapshot.setId(persisted.getId()); |
| 203 | + terminalSnapshot.setState(FlinkAppStateEnum.CANCELED.getValue()); |
| 204 | + terminalSnapshot.setOptionState(OptionStateEnum.NONE.getValue()); |
| 205 | + applicationManageService.persistMetrics(terminalSnapshot); |
| 206 | + |
| 207 | + FlinkApplication actual = applicationManageService.getById(persisted.getId()); |
| 208 | + assertThat(actual.getState()).isEqualTo(FlinkAppStateEnum.CANCELED.getValue()); |
| 209 | + assertThat(actual.getOptionState()).isEqualTo(OptionStateEnum.NONE.getValue()); |
| 210 | + } |
| 211 | + |
| 212 | + @Test |
| 213 | + void testPersistMetricsRejectsLateNonTerminalSnapshotAfterCancellationCompletes() { |
| 214 | + assertCompletedCancellationRejectsLateSnapshot( |
| 215 | + FlinkAppStateEnum.FAILING, OptionStateEnum.NONE); |
| 216 | + assertCompletedCancellationRejectsLateSnapshot( |
| 217 | + FlinkAppStateEnum.RUNNING, OptionStateEnum.NONE); |
| 218 | + assertCompletedCancellationRejectsLateSnapshot( |
| 219 | + FlinkAppStateEnum.CANCELLING, OptionStateEnum.CANCELLING); |
| 220 | + } |
| 221 | + |
| 222 | + @Test |
| 223 | + void testPersistMetricsAllowsExplicitRestartAfterCancellationCompletes() { |
| 224 | + FlinkApplication persisted = createApplication( |
| 225 | + FlinkAppStateEnum.CANCELED, OptionStateEnum.NONE); |
| 226 | + |
| 227 | + FlinkApplication starting = new FlinkApplication(); |
| 228 | + starting.setId(persisted.getId()); |
| 229 | + starting.setState(FlinkAppStateEnum.STARTING.getValue()); |
| 230 | + assertThat(applicationManageService.updateById(starting)).isTrue(); |
| 231 | + |
| 232 | + FlinkApplication runningSnapshot = new FlinkApplication(); |
| 233 | + runningSnapshot.setId(persisted.getId()); |
| 234 | + runningSnapshot.setState(FlinkAppStateEnum.RUNNING.getValue()); |
| 235 | + runningSnapshot.setOptionState(OptionStateEnum.NONE.getValue()); |
| 236 | + runningSnapshot.setTotalTask(2); |
| 237 | + applicationManageService.persistMetrics(runningSnapshot); |
| 238 | + |
| 239 | + FlinkApplication actual = applicationManageService.getById(persisted.getId()); |
| 240 | + assertThat(actual.getState()).isEqualTo(FlinkAppStateEnum.RUNNING.getValue()); |
| 241 | + assertThat(actual.getOptionState()).isEqualTo(OptionStateEnum.NONE.getValue()); |
| 242 | + assertThat(actual.getTotalTask()).isEqualTo(2); |
| 243 | + } |
| 244 | + |
| 245 | + @Test |
| 246 | + void testPersistMetricsAllowsTerminalCorrectionAfterCancellationCompletes() { |
| 247 | + FlinkApplication persisted = createApplication( |
| 248 | + FlinkAppStateEnum.CANCELED, OptionStateEnum.NONE); |
| 249 | + |
| 250 | + FlinkApplication failedSnapshot = new FlinkApplication(); |
| 251 | + failedSnapshot.setId(persisted.getId()); |
| 252 | + failedSnapshot.setState(FlinkAppStateEnum.FAILED.getValue()); |
| 253 | + failedSnapshot.setOptionState(OptionStateEnum.NONE.getValue()); |
| 254 | + applicationManageService.persistMetrics(failedSnapshot); |
| 255 | + |
| 256 | + FlinkApplication actual = applicationManageService.getById(persisted.getId()); |
| 257 | + assertThat(actual.getState()).isEqualTo(FlinkAppStateEnum.FAILED.getValue()); |
| 258 | + assertThat(actual.getOptionState()).isEqualTo(OptionStateEnum.NONE.getValue()); |
| 259 | + } |
| 260 | + |
| 261 | + @Test |
| 262 | + void testPersistMetricsDoesNotFreezeRecoverableLostState() { |
| 263 | + FlinkApplication persisted = createApplication( |
| 264 | + FlinkAppStateEnum.LOST, OptionStateEnum.NONE); |
| 265 | + |
| 266 | + FlinkApplication recoveredSnapshot = new FlinkApplication(); |
| 267 | + recoveredSnapshot.setId(persisted.getId()); |
| 268 | + recoveredSnapshot.setState(FlinkAppStateEnum.RUNNING.getValue()); |
| 269 | + recoveredSnapshot.setOptionState(OptionStateEnum.NONE.getValue()); |
| 270 | + applicationManageService.persistMetrics(recoveredSnapshot); |
| 271 | + |
| 272 | + FlinkApplication actual = applicationManageService.getById(persisted.getId()); |
| 273 | + assertThat(actual.getState()).isEqualTo(FlinkAppStateEnum.RUNNING.getValue()); |
| 274 | + assertThat(actual.getOptionState()).isEqualTo(OptionStateEnum.NONE.getValue()); |
| 275 | + } |
| 276 | + |
| 277 | + private void assertCompletedCancellationRejectsLateSnapshot( |
| 278 | + FlinkAppStateEnum lateState, |
| 279 | + OptionStateEnum lateOptionState) { |
| 280 | + FlinkApplication persisted = createApplication( |
| 281 | + FlinkAppStateEnum.CANCELLING, OptionStateEnum.CANCELLING); |
| 282 | + |
| 283 | + FlinkApplication terminalSnapshot = new FlinkApplication(); |
| 284 | + terminalSnapshot.setId(persisted.getId()); |
| 285 | + terminalSnapshot.setState(FlinkAppStateEnum.CANCELED.getValue()); |
| 286 | + terminalSnapshot.setOptionState(OptionStateEnum.NONE.getValue()); |
| 287 | + applicationManageService.persistMetrics(terminalSnapshot); |
| 288 | + |
| 289 | + FlinkApplication lateSnapshot = new FlinkApplication(); |
| 290 | + lateSnapshot.setId(persisted.getId()); |
| 291 | + lateSnapshot.setState(lateState.getValue()); |
| 292 | + lateSnapshot.setOptionState(lateOptionState.getValue()); |
| 293 | + lateSnapshot.setTotalTask(7); |
| 294 | + applicationManageService.persistMetrics(lateSnapshot); |
| 295 | + |
| 296 | + FlinkApplication actual = applicationManageService.getById(persisted.getId()); |
| 297 | + assertThat(actual.getState()).isEqualTo(FlinkAppStateEnum.CANCELED.getValue()); |
| 298 | + assertThat(actual.getOptionState()).isEqualTo(OptionStateEnum.NONE.getValue()); |
| 299 | + assertThat(actual.getTotalTask()).isNull(); |
| 300 | + } |
| 301 | + |
| 302 | + private void assertInterruptedCancellationRecovers(FlinkAppStateEnum currentState) { |
| 303 | + FlinkApplication persisted = createApplication( |
| 304 | + FlinkAppStateEnum.CANCELLING, OptionStateEnum.NONE); |
| 305 | + |
| 306 | + FlinkApplication currentSnapshot = new FlinkApplication(); |
| 307 | + currentSnapshot.setId(persisted.getId()); |
| 308 | + currentSnapshot.setState(currentState.getValue()); |
| 309 | + currentSnapshot.setOptionState(OptionStateEnum.NONE.getValue()); |
| 310 | + currentSnapshot.setTotalTask(4); |
| 311 | + applicationManageService.persistMetrics(currentSnapshot); |
| 312 | + |
| 313 | + FlinkApplication actual = applicationManageService.getById(persisted.getId()); |
| 314 | + assertThat(actual.getState()).isEqualTo(currentState.getValue()); |
| 315 | + assertThat(actual.getOptionState()).isEqualTo(OptionStateEnum.NONE.getValue()); |
| 316 | + assertThat(actual.getTotalTask()).isEqualTo(4); |
| 317 | + } |
| 318 | + |
| 319 | + private void assertNonTerminalMetricsPreserveOperation(OptionStateEnum optionState) { |
| 320 | + FlinkApplication persisted = createApplication(FlinkAppStateEnum.CANCELLING, optionState); |
| 321 | + |
| 322 | + FlinkApplication staleSnapshot = new FlinkApplication(); |
| 323 | + staleSnapshot.setId(persisted.getId()); |
| 324 | + staleSnapshot.setState(FlinkAppStateEnum.FAILING.getValue()); |
| 325 | + staleSnapshot.setOptionState(OptionStateEnum.NONE.getValue()); |
| 326 | + staleSnapshot.setTotalTask(3); |
| 327 | + applicationManageService.persistMetrics(staleSnapshot); |
| 328 | + |
| 329 | + FlinkApplication actual = applicationManageService.getById(persisted.getId()); |
| 330 | + assertThat(actual.getState()).isEqualTo(FlinkAppStateEnum.CANCELLING.getValue()); |
| 331 | + assertThat(actual.getOptionState()).isEqualTo(optionState.getValue()); |
| 332 | + assertThat(actual.getTotalTask()).isEqualTo(3); |
| 333 | + } |
| 334 | + |
| 335 | + private FlinkApplication createApplication( |
| 336 | + FlinkAppStateEnum state, |
| 337 | + OptionStateEnum optionState) { |
| 338 | + FlinkApplication application = new FlinkApplication(); |
| 339 | + application.setTeamId(1L); |
| 340 | + application.setState(state.getValue()); |
| 341 | + application.setOptionState(optionState.getValue()); |
| 342 | + assertThat(applicationManageService.save(application)).isTrue(); |
| 343 | + return application; |
| 344 | + } |
149 | 345 | } |
0 commit comments