diff --git a/cloud/flamingock-cloud/src/main/java/io/flamingock/cloud/audit/HtttpAuditWriter.java b/cloud/flamingock-cloud/src/main/java/io/flamingock/cloud/audit/HtttpAuditWriter.java index 8e6f605d9..301b5ca2f 100644 --- a/cloud/flamingock-cloud/src/main/java/io/flamingock/cloud/audit/HtttpAuditWriter.java +++ b/cloud/flamingock-cloud/src/main/java/io/flamingock/cloud/audit/HtttpAuditWriter.java @@ -76,7 +76,7 @@ public Result writeEntry(AuditEntry auditEntry) { .execute(); return Result.OK(); } catch (Throwable throwable) { - logger.error("Error writing audit [{}] :\n{}", auditEntry.getTaskId(), throwable.toString()); + logger.debug("Error writing audit [{}] :\n{}", auditEntry.getTaskId(), throwable.toString()); return new Result.Error(throwable); } diff --git a/core/flamingock-core-commons/src/main/java/io/flamingock/internal/common/core/error/FlamingockException.java b/core/flamingock-core-commons/src/main/java/io/flamingock/internal/common/core/error/FlamingockException.java index 66588f78d..44e345b8f 100644 --- a/core/flamingock-core-commons/src/main/java/io/flamingock/internal/common/core/error/FlamingockException.java +++ b/core/flamingock-core-commons/src/main/java/io/flamingock/internal/common/core/error/FlamingockException.java @@ -22,10 +22,6 @@ public class FlamingockException extends RuntimeException { - public FlamingockException() { - super(); - } - public FlamingockException(Throwable cause) { super(cause); } @@ -34,16 +30,12 @@ public FlamingockException(String message) { super(message); } - public FlamingockException(String formattedMessage, Object... args) { - super(String.format(formattedMessage, args)); - } - - public FlamingockException(Throwable cause, String formattedMessage, Object... args) { - this(String.format(formattedMessage, args), cause); + public FlamingockException(String message, Throwable cause) { + super(message, cause); } - public FlamingockException(Throwable cause, String message) { - super(message, cause); + public FlamingockException(String message, Object... args) { + super(String.format(message, args)); } } diff --git a/core/flamingock-core-commons/src/main/java/io/flamingock/internal/common/core/recovery/action/ChangeActionResolver.java b/core/flamingock-core-commons/src/main/java/io/flamingock/internal/common/core/recovery/action/ChangeActionResolver.java index 6559a250e..50823c9f3 100644 --- a/core/flamingock-core-commons/src/main/java/io/flamingock/internal/common/core/recovery/action/ChangeActionResolver.java +++ b/core/flamingock-core-commons/src/main/java/io/flamingock/internal/common/core/recovery/action/ChangeActionResolver.java @@ -64,7 +64,6 @@ public static ChangeAction resolve(AuditEntry auditEntry) { return MANUAL_INTERVENTION; } - case MANUAL_MARKED_AS_ROLLED_BACK: case FAILED: if (txStrategy == null || txStrategy == AuditTxType.NON_TX) { if (auditEntry.getRecoveryStrategy().isAlwaysRetry()) { @@ -85,6 +84,7 @@ public static ChangeAction resolve(AuditEntry auditEntry) { return APPLY; } + case MANUAL_MARKED_AS_ROLLED_BACK: case ROLLED_BACK: log.debug("Change[{}] in state='{}}' (TxType={}}) -> Action={}} | Reason: {}", auditEntry.getTaskId(), status, txStrategy, APPLY, diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/pipeline/execution/StageExecutionException.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/pipeline/execution/StageExecutionException.java index c0d3ca11b..dd783102e 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/pipeline/execution/StageExecutionException.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/pipeline/execution/StageExecutionException.java @@ -19,16 +19,17 @@ public class StageExecutionException extends FlamingockException { - private final StageSummary summary; - - - public StageExecutionException(StageSummary summary) { - super("\n\n" + summary.getPretty() + "\n"); - this.summary = summary; + public static StageExecutionException fromExisting(Throwable exception, StageSummary summary) { + Throwable cause = exception.getCause(); + return (exception instanceof FlamingockException) && cause != null + ? new StageExecutionException(cause, summary) + : new StageExecutionException(exception, summary); } - public StageExecutionException(Throwable throwable, StageSummary summary) { - super(throwable); + private final StageSummary summary; + + private StageExecutionException(Throwable cause, StageSummary summary) { + super(cause); this.summary = summary; } diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/pipeline/execution/StageExecutor.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/pipeline/execution/StageExecutor.java index b84d577a5..40ee4ca33 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/pipeline/execution/StageExecutor.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/pipeline/execution/StageExecutor.java @@ -23,6 +23,8 @@ import io.flamingock.internal.core.store.lock.Lock; import io.flamingock.internal.core.targets.TargetSystemManager; import io.flamingock.internal.core.task.executable.ExecutableTask; +import io.flamingock.internal.core.task.navigation.FailedChangeProcessResult; +import io.flamingock.internal.core.task.navigation.navigator.ChangeProcessResult; import io.flamingock.internal.core.task.navigation.navigator.ChangeProcessStrategy; import io.flamingock.internal.core.task.navigation.navigator.ChangeProcessStrategyFactory; import io.flamingock.internal.core.transaction.TransactionWrapper; @@ -78,23 +80,24 @@ public Output executeStage(ExecutableStage executableStage, .map(changeProcessFactory::setChange) .map(ChangeProcessStrategyFactory::build) .map(ChangeProcessStrategy::applyChange) - .peek(taskSummary -> { - summary.addSummary(taskSummary); - if (taskSummary.isFailed()) { + .peek(result -> { + summary.addSummary(result.getSummary()); + if (result.isFailed()) { logger.error("Change failed [change={} stage={}]", - taskSummary.getId(), stageName); + result.getChangeId(), stageName); } else { logger.debug("Change completed successfully [change={} stage={}]", - taskSummary.getId(), stageName); + result.getChangeId(), stageName); } }) - .filter(TaskSummary::isFailed) + .filter(ChangeProcessResult::isFailed) .findFirst() - .ifPresent(failed -> { + .map(processResult -> (FailedChangeProcessResult)processResult) + .ifPresent(failedResult -> { Duration stageDuration = Duration.between(stageStart, LocalDateTime.now()); - logger.error("Stage execution failed [stage={} duration={} failed_change={}]", - stageName, formatDuration(stageDuration), failed.getId()); - throw new StageExecutionException(summary); + logger.debug("Stage execution failed [stage={} duration={} failed_change={}]", + stageName, formatDuration(stageDuration), failedResult.getChangeId()); + throw StageExecutionException.fromExisting(failedResult.getException(), summary); }); Duration stageDuration = Duration.between(stageStart, LocalDateTime.now()); @@ -102,15 +105,12 @@ public Output executeStage(ExecutableStage executableStage, stageName, formatDuration(stageDuration), taskCount); } catch (StageExecutionException stageExecutionException) { - Duration stageDuration = Duration.between(stageStart, LocalDateTime.now()); - logger.error("Stage execution failed [stage={} duration={}]", - stageName, formatDuration(stageDuration)); throw stageExecutionException; } catch (Throwable throwable) { Duration stageDuration = Duration.between(stageStart, LocalDateTime.now()); - logger.error("Stage execution failed with unexpected error [stage={} duration={} error={}]", + logger.debug("Stage execution failed with unexpected error [stage={} duration={} error={}]", stageName, formatDuration(stageDuration), throwable.getMessage(), throwable); - throw new StageExecutionException(throwable, summary); + throw StageExecutionException.fromExisting(throwable, summary); } return new Output(summary); diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/runner/PipelineExecutionException.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/runner/PipelineExecutionException.java index 55c2a220c..c056cd9aa 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/runner/PipelineExecutionException.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/runner/PipelineExecutionException.java @@ -19,15 +19,17 @@ public class PipelineExecutionException extends FlamingockException { - private final PipelineSummary summary; + public static PipelineExecutionException fromExisting(Throwable exception, PipelineSummary summary) { + Throwable cause = exception.getCause(); + return (exception instanceof FlamingockException) && cause != null + ? new PipelineExecutionException(cause, summary) + : new PipelineExecutionException(exception, summary); + } + private final PipelineSummary summary; - public PipelineExecutionException(PipelineSummary summary) { - super("\n\n" + summary.getPretty() + "\n"); - this.summary = summary; - } - public PipelineExecutionException(Throwable throwable, PipelineSummary summary) { + private PipelineExecutionException(Throwable throwable, PipelineSummary summary) { super(throwable); this.summary = summary; } diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/runner/PipelineRunner.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/runner/PipelineRunner.java index 2a661e97c..dd3f3add6 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/runner/PipelineRunner.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/runner/PipelineRunner.java @@ -15,12 +15,7 @@ */ package io.flamingock.internal.core.runner; -import io.flamingock.internal.util.id.RunnerId; import io.flamingock.internal.common.core.error.FlamingockException; -import io.flamingock.internal.core.plan.ExecutionPlan; -import io.flamingock.internal.core.plan.ExecutionPlanner; -import io.flamingock.internal.core.store.lock.Lock; -import io.flamingock.internal.core.store.lock.LockException; import io.flamingock.internal.core.event.EventPublisher; import io.flamingock.internal.core.event.model.impl.PipelineCompletedEvent; import io.flamingock.internal.core.event.model.impl.PipelineFailedEvent; @@ -29,13 +24,18 @@ import io.flamingock.internal.core.event.model.impl.StageFailedEvent; import io.flamingock.internal.core.event.model.impl.StageStartedEvent; import io.flamingock.internal.core.pipeline.execution.ExecutableStage; -import io.flamingock.internal.core.pipeline.loaded.stage.AbstractLoadedStage; -import io.flamingock.internal.core.pipeline.loaded.LoadedPipeline; import io.flamingock.internal.core.pipeline.execution.ExecutionContext; import io.flamingock.internal.core.pipeline.execution.OrphanExecutionContext; import io.flamingock.internal.core.pipeline.execution.StageExecutionException; import io.flamingock.internal.core.pipeline.execution.StageExecutor; import io.flamingock.internal.core.pipeline.execution.StageSummary; +import io.flamingock.internal.core.pipeline.loaded.LoadedPipeline; +import io.flamingock.internal.core.pipeline.loaded.stage.AbstractLoadedStage; +import io.flamingock.internal.core.plan.ExecutionPlan; +import io.flamingock.internal.core.plan.ExecutionPlanner; +import io.flamingock.internal.core.store.lock.Lock; +import io.flamingock.internal.core.store.lock.LockException; +import io.flamingock.internal.util.id.RunnerId; import io.flamingock.internal.util.log.FlamingockLoggerFactory; import org.slf4j.Logger; @@ -82,6 +82,15 @@ public PipelineRunner(RunnerId runnerId, this.finalizer = finalizer; } + private static List validateAndGetExecutableStages(LoadedPipeline pipeline) { + pipeline.validate(); + List stages = new ArrayList<>(); + if (pipeline.getSystemStage().isPresent()) { + stages.add(pipeline.getSystemStage().get()); + } + stages.addAll(pipeline.getStages()); + return stages; + } private void run(LoadedPipeline pipeline) throws FlamingockException { @@ -93,7 +102,7 @@ private void run(LoadedPipeline pipeline) throws FlamingockException { // Validate execution plan for manual intervention requirements // This centralized validation ensures both community and cloud paths are validated execution.validate(); - + if (pipelineSummary == null) { pipelineSummary = new PipelineSummary(execution.getPipeline()); } @@ -111,7 +120,7 @@ private void run(LoadedPipeline pipeline) throws FlamingockException { eventPublisher.publish(new StageFailedEvent(exception)); eventPublisher.publish(new PipelineFailedEvent(exception)); if (throwExceptionIfCannotObtainLock) { - logger.error("Required process lock not acquired - ABORTING OPERATION", exception); + logger.debug("Required process lock not acquired - ABORTING OPERATION", exception); throw exception; } else { logger.warn("Process lock not acquired but throwExceptionIfCannotObtainLock=false - CONTINUING WITHOUT LOCK", exception); @@ -121,7 +130,7 @@ private void run(LoadedPipeline pipeline) throws FlamingockException { //if it's a StageExecutionException, we can safely assume the stage started its //execution, therefor the pipelinesSummary is initialised requireNonNull(pipelineSummary).merge(e.getSummary()); - throw new PipelineExecutionException(pipelineSummary); + throw PipelineExecutionException.fromExisting(e.getCause(), pipelineSummary); } } while (true); @@ -131,17 +140,6 @@ private void run(LoadedPipeline pipeline) throws FlamingockException { eventPublisher.publish(new PipelineCompletedEvent()); } - private static List validateAndGetExecutableStages(LoadedPipeline pipeline) { - pipeline.validate(); - List stages = new ArrayList<>(); - if(pipeline.getSystemStage().isPresent()) { - stages.add(pipeline.getSystemStage().get()); - } - stages.addAll(pipeline.getStages()); - return stages; - } - - private StageSummary runStage(String executionId, Lock lock, ExecutableStage executableStage) { try { return startStage(executionId, lock, executableStage); @@ -164,12 +162,24 @@ private StageSummary startStage(String executionId, Lock lock, ExecutableStage e return executionOutput.getSummary(); } - private FlamingockException processAndGetFlamingockException(Throwable generalException) throws FlamingockException { - FlamingockException exception = generalException instanceof FlamingockException ? (FlamingockException) generalException : new FlamingockException(generalException); - logger.error("Error executing the process. ABORTED OPERATION", exception); - eventPublisher.publish(new StageFailedEvent(exception)); - eventPublisher.publish(new PipelineFailedEvent(exception)); - return exception; + private FlamingockException processAndGetFlamingockException(Throwable exception) throws FlamingockException { + FlamingockException flamingockException; + if (exception instanceof PipelineExecutionException) { + PipelineExecutionException pipelineException = (PipelineExecutionException) exception; + if (pipelineException.getCause() instanceof FlamingockException) { + flamingockException = (FlamingockException) pipelineException.getCause(); + } else { + flamingockException = (PipelineExecutionException) exception; + } + } else if (exception instanceof FlamingockException) { + flamingockException = (FlamingockException) exception; + } else { + flamingockException = new FlamingockException(exception); + } + logger.debug("Error executing the process. ABORTED OPERATION", exception); + eventPublisher.publish(new StageFailedEvent(flamingockException)); + eventPublisher.publish(new PipelineFailedEvent(flamingockException)); + return flamingockException; } @Override diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/runtime/ExecutionRuntime.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/runtime/ExecutionRuntime.java index 31ee77a1f..283d82873 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/runtime/ExecutionRuntime.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/runtime/ExecutionRuntime.java @@ -36,6 +36,7 @@ import javax.inject.Named; import java.lang.reflect.Constructor; import java.lang.reflect.Executable; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Parameter; import java.util.ArrayList; @@ -118,7 +119,14 @@ public Object executeMethodWithParameters(Object instance, Method method, Object try { return method.invoke(instance, parameters); } catch (Exception e) { - throw new RuntimeException(e); + if(e instanceof FlamingockException) { + throw (FlamingockException)e; + } else { + throw e instanceof InvocationTargetException + ? new FlamingockException(((InvocationTargetException)e).getTargetException()) + : new FlamingockException(e); + + } } } diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/runtime/MissingInjectedParameterException.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/runtime/MissingInjectedParameterException.java index 0d0499165..e85d07afb 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/runtime/MissingInjectedParameterException.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/runtime/MissingInjectedParameterException.java @@ -24,7 +24,7 @@ public class MissingInjectedParameterException extends FlamingockException { private final String name; public MissingInjectedParameterException(Class wrongParameter, String name) { - super(); + super(buildMessage(wrongParameter, name)); this.wrongParameter = wrongParameter; this.name = name; } @@ -37,12 +37,11 @@ public String getName() { return name; } - @Override - public String getMessage() { + private static String buildMessage(Class wrongParameter, String name) { StringBuilder sb = new StringBuilder("Wrong parameter[") - .append(getWrongParameter().getSimpleName()) + .append(wrongParameter.getSimpleName()) .append("]"); if (name != null) { sb.append(" with name: ") diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/store/audit/domain/RuntimeContext.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/store/audit/domain/RuntimeContext.java index 3ccc41cbb..732c42b6c 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/store/audit/domain/RuntimeContext.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/store/audit/domain/RuntimeContext.java @@ -139,7 +139,7 @@ public Builder setAutoRollbackStep(CompleteAutoRolledBackStep rolledBackStep) { private void setResult(TaskStep taskStep) { if (taskStep instanceof FailedWithErrorStep) { executionResult = ExecutionResult.FAILED; - error = ((FailedWithErrorStep) taskStep).getError(); + error = ((FailedWithErrorStep) taskStep).getMainError(); } else { executionResult = ExecutionResult.SUCCESS; error = null; diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/store/lock/Lock.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/store/lock/Lock.java index 608a287b6..756269aad 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/store/lock/Lock.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/store/lock/Lock.java @@ -229,7 +229,7 @@ protected void waitForLock(LocalDateTime expiresAt) { TimeUtil.millisToMinutes(sleepingMillis)); Thread.sleep(sleepingMillis); } catch (InterruptedException ex) { - logger.error("ERROR acquiring the lock", ex); + logger.warn("ERROR acquiring the lock", ex); Thread.currentThread().interrupt(); } } diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/store/lock/LockException.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/store/lock/LockException.java index b5ebf7dad..187324495 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/store/lock/LockException.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/store/lock/LockException.java @@ -26,7 +26,4 @@ public LockException(String s) { super(s); } - public LockException() { - super(); - } } diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/targets/TargetSystemManager.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/targets/TargetSystemManager.java index fe0892099..93e795eb1 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/targets/TargetSystemManager.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/targets/TargetSystemManager.java @@ -112,7 +112,7 @@ public TargetSystemOps getTargetSystem(String id) { "Change requires a valid targetSystem. Found: [%s]. Available target systems: [%s]", id, availableTargetSystems ); - logger.error(message); + logger.debug(message); throw new FlamingockException(message); } else { AbstractTargetSystem targetSystem = targetSystemMap.get(id); diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/executable/ReflectionExecutableTask.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/executable/ReflectionExecutableTask.java index 320202ed9..282e2f24e 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/executable/ReflectionExecutableTask.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/executable/ReflectionExecutableTask.java @@ -15,6 +15,7 @@ */ package io.flamingock.internal.core.task.executable; +import io.flamingock.internal.common.core.error.ChangeExecutionException; import io.flamingock.internal.core.runtime.ExecutionRuntime; import io.flamingock.internal.core.task.loaded.AbstractReflectionLoadedTask; import io.flamingock.internal.common.core.recovery.action.ChangeAction; @@ -75,7 +76,11 @@ public void execute(ExecutionRuntime executionRuntime) { protected void executeInternal(ExecutionRuntime executionRuntime, Method method ) { Object instance = executionRuntime.getInstance(descriptor.getConstructor()); - executionRuntime.executeMethodWithInjectedDependencies(instance, method); + try { + executionRuntime.executeMethodWithInjectedDependencies(instance, method); + } catch (Throwable ex) { + throw new ChangeExecutionException(ex.getMessage(), this.getId(), ex); + } } @Override diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/executable/TemplateExecutableTask.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/executable/TemplateExecutableTask.java index 44c944780..ad5b4af5a 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/executable/TemplateExecutableTask.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/executable/TemplateExecutableTask.java @@ -16,6 +16,7 @@ package io.flamingock.internal.core.task.executable; import io.flamingock.api.template.ChangeTemplate; +import io.flamingock.internal.common.core.error.ChangeExecutionException; import io.flamingock.internal.core.runtime.ExecutionRuntime; import io.flamingock.internal.core.task.loaded.TemplateLoadedChange; import io.flamingock.internal.common.core.recovery.action.ChangeAction; @@ -39,15 +40,19 @@ public TemplateExecutableTask(String stageName, @Override protected void executeInternal(ExecutionRuntime executionRuntime, Method method ) { - logger.debug("Starting execution of change[{}] with template: {}", descriptor.getId(), descriptor.getTemplateClass()); - logger.debug("change[{}] transactional: {}", descriptor.getId(), descriptor.isTransactional()); - Object instance = executionRuntime.getInstance(descriptor.getConstructor()); - ChangeTemplate changeTemplateInstance = (ChangeTemplate) instance; - changeTemplateInstance.setTransactional(descriptor.isTransactional()); - setExecutionData(executionRuntime, changeTemplateInstance, "Configuration"); - setExecutionData(executionRuntime, changeTemplateInstance, "ApplyPayload"); - setExecutionData(executionRuntime, changeTemplateInstance, "RollbackPayload"); - executionRuntime.executeMethodWithInjectedDependencies(instance, method); + try { + logger.debug("Starting execution of change[{}] with template: {}", descriptor.getId(), descriptor.getTemplateClass()); + logger.debug("change[{}] transactional: {}", descriptor.getId(), descriptor.isTransactional()); + Object instance = executionRuntime.getInstance(descriptor.getConstructor()); + ChangeTemplate changeTemplateInstance = (ChangeTemplate) instance; + changeTemplateInstance.setTransactional(descriptor.isTransactional()); + setExecutionData(executionRuntime, changeTemplateInstance, "Configuration"); + setExecutionData(executionRuntime, changeTemplateInstance, "ApplyPayload"); + setExecutionData(executionRuntime, changeTemplateInstance, "RollbackPayload"); + executionRuntime.executeMethodWithInjectedDependencies(instance, method); + } catch (Throwable ex) { + throw new ChangeExecutionException(ex.getMessage(), this.getId(), ex); + } } diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/FailedChangeProcessResult.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/FailedChangeProcessResult.java new file mode 100644 index 000000000..ba01cb4f0 --- /dev/null +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/FailedChangeProcessResult.java @@ -0,0 +1,37 @@ +/* + * Copyright 2025 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.internal.core.task.navigation; + +import io.flamingock.internal.core.pipeline.execution.TaskSummary; +import io.flamingock.internal.core.task.navigation.navigator.ChangeProcessResult; + +public class FailedChangeProcessResult extends ChangeProcessResult { + private final Throwable exception; + + public FailedChangeProcessResult(String changeId, TaskSummary summary, Throwable exception) { + super(changeId, summary); + this.exception = exception; + } + + public Throwable getException() { + return exception; + } + + @Override + public boolean isFailed() { + return true; + } +} diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/ChangeProcessLogger.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/ChangeProcessLogger.java index e3237ccbe..436bbe9d4 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/ChangeProcessLogger.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/ChangeProcessLogger.java @@ -20,7 +20,7 @@ import io.flamingock.internal.core.task.executable.ExecutableTask; import io.flamingock.internal.core.task.navigation.step.execution.ExecutionStep; import io.flamingock.internal.core.task.navigation.step.execution.FailedExecutionStep; -import io.flamingock.internal.core.task.navigation.step.execution.SuccessExecutionStep; +import io.flamingock.internal.core.task.navigation.step.execution.SuccessApplyStep; import io.flamingock.internal.core.task.navigation.step.rolledback.FailedManualRolledBackStep; import io.flamingock.internal.core.task.navigation.step.rolledback.ManualRolledBackStep; import io.flamingock.internal.util.Result; @@ -35,39 +35,39 @@ public class ChangeProcessLogger { private static final String MANUAL_ROLLBACK_DESC = "manual-rollback"; private static final String AUTO_ROLLBACK_DESC = "auto-rollback"; - public void logChangeExecutionStart(String changeId) { - logger.info("Starting change execution [change={}]", changeId); + public void logStartChangeProcessStrategy(String changeId) { + logger.debug("Starting change process strategy build [change= {}]", changeId); } - + public void logTargetSystemResolved(String changeId, TargetSystemDescriptor targetSystem) { String targetSystemId = targetSystem != null ? targetSystem.getId() : null; - logger.debug("Target system resolved [change={}, targetSystem={}]", changeId, targetSystemId); + logger.debug("Target system resolved [change= {}, targetSystem= {}]", changeId, targetSystemId); } public void logStrategyApplication(String changeId, String targetSystemId, String strategyType) { - logger.info("Applying change [change={}, target={}, strategy={}]", changeId, targetSystemId, strategyType); + logger.info("Starting change [change= {}, target= {}, strategy= {}]", changeId, targetSystemId, strategyType); } public void logSkippedExecution(String changeId) { - logger.info("SKIPPED [change={}, reason=already applied]", changeId); + logger.info("SKIPPED [change= {}, reason=already applied]", changeId); } public void logExecutionResult(ExecutionStep executionStep) { String taskId = executionStep.getTask().getId(); String duration = formatDuration(executionStep.getDuration()); - if (executionStep instanceof SuccessExecutionStep) { - logger.info("APPLIED [change={}, duration={}]", taskId, duration); + if (executionStep instanceof SuccessApplyStep) { + logger.info("APPLIED [change= {}, duration= {}]", taskId, duration); } else if (executionStep instanceof FailedExecutionStep) { FailedExecutionStep failed = (FailedExecutionStep) executionStep; - logger.error("FAILED [change={}, duration={}, error={}]", - taskId, duration, failed.getError().getMessage(), failed.getError()); + logger.error("FAILED [change= {}, duration= {}] : {}", + taskId, duration, failed.getMainError().getMessage()); } } public void logAutoRollback(ExecutableTask executableChange, long duration) { String formattedDuration = formatDuration(duration); - logger.info("ROLLED_BACK [change={}, duration={}]", executableChange.getId(), formattedDuration); + logger.info("ROLLED_BACK [change= {}, duration= {}]", executableChange.getId(), formattedDuration); } public void logManualRollbackResult(ManualRolledBackStep rolledBack) { @@ -76,19 +76,19 @@ public void logManualRollbackResult(ManualRolledBackStep rolledBack) { if (rolledBack instanceof FailedManualRolledBackStep) { FailedManualRolledBackStep failed = (FailedManualRolledBackStep) rolledBack; - logger.error("ROLLBACK_FAILED [change={}, duration={}, error={}]", - taskId, duration, failed.getError().getMessage(), failed.getError()); + logger.error("ROLLBACK_FAILED [change= {}, duration= {}] : {}", + taskId, duration, failed.getMainError().getMessage()); } else { - logger.info("ROLLED_BACK [change={}, duration={}]", taskId, duration); + logger.info("ROLLED_BACK [change= {}, duration= {}]", taskId, duration); } } public void logAuditResult(Result auditResult, String id, String description) { if (auditResult instanceof Result.Error) { - logger.error("Audit operation failed [change={}, operation={}, error={}]", + logger.error("Audit operation failed [change= {}, operation= {}] : {}", id, description, ((Result.Error) auditResult).getError().getMessage()); } else { - logger.debug("Audit operation completed successfully [change={}, operation={}]", id, description); + logger.debug("Audit operation completed successfully [change= {}, operation= {}]", id, description); } } diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/ChangeProcessResult.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/ChangeProcessResult.java new file mode 100644 index 000000000..c0e8753c9 --- /dev/null +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/ChangeProcessResult.java @@ -0,0 +1,41 @@ +/* + * Copyright 2025 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.internal.core.task.navigation.navigator; + +import io.flamingock.internal.core.pipeline.execution.TaskSummary; + +public class ChangeProcessResult { + + private final String changeId; + private final TaskSummary summary; + + public ChangeProcessResult(String changeId, TaskSummary summary) { + this.changeId = changeId; + this.summary = summary; + } + + public String getChangeId() { + return changeId; + } + + public TaskSummary getSummary() { + return summary; + } + + public boolean isFailed() { + return false; + } +} diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/ChangeProcessStrategy.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/ChangeProcessStrategy.java index 33c8c79e9..284f5ad0a 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/ChangeProcessStrategy.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/ChangeProcessStrategy.java @@ -19,5 +19,5 @@ public interface ChangeProcessStrategy { - TaskSummary applyChange(); + ChangeProcessResult applyChange(); } diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/ChangeProcessStrategyFactory.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/ChangeProcessStrategyFactory.java index 80c31f582..f1924f1e5 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/ChangeProcessStrategyFactory.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/ChangeProcessStrategyFactory.java @@ -105,7 +105,7 @@ public ChangeProcessStrategyFactory setExecutionContext(ExecutionContext executi public ChangeProcessStrategy build() { - changeLogger.logChangeExecutionStart(change.getId()); + changeLogger.logStartChangeProcessStrategy(change.getId()); TargetSystemOps targetSystemOps = targetSystemManager.getTargetSystem(change.getTargetSystem()); diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/strategy/AbstractChangeProcessStrategy.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/strategy/AbstractChangeProcessStrategy.java index d67d00857..b0663fb32 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/strategy/AbstractChangeProcessStrategy.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/strategy/AbstractChangeProcessStrategy.java @@ -26,6 +26,7 @@ import io.flamingock.internal.core.runtime.proxy.LockGuardProxyFactory; import io.flamingock.internal.core.targets.operations.TargetSystemOps; import io.flamingock.internal.core.task.executable.ExecutableTask; +import io.flamingock.internal.core.task.navigation.navigator.ChangeProcessResult; import io.flamingock.internal.core.task.navigation.navigator.ChangeProcessStrategy; import io.flamingock.internal.core.task.navigation.navigator.ChangeProcessLogger; import io.flamingock.internal.core.task.navigation.navigator.AuditStoreStepOperations; @@ -112,15 +113,16 @@ protected AbstractChangeProcessStrategy(ExecutableTask change, } - public final TaskSummary applyChange() { + public final ChangeProcessResult applyChange() { if (!change.isAlreadyApplied()) { return doApplyChange(); } else { stepLogger.logSkippedExecution(change.getId()); - return summarizer + TaskSummary summary = summarizer .add(new CompletedAlreadyAppliedStep(change)) .setSuccessful() .getSummary(); + return new ChangeProcessResult(change.getId(), summary); } } @@ -132,7 +134,7 @@ public final TaskSummary applyChange() { * * @return Task execution summary with success/failure status and step details */ - abstract protected TaskSummary doApplyChange(); + abstract protected ChangeProcessResult doApplyChange(); /** * Audits and logs the start of change execution. @@ -163,7 +165,7 @@ protected AfterExecutionAuditStep auditAndLogExecution(ExecutionStep executionSt Result auditResult = auditStoreOperations.auditExecution(executionStep, executionContext, auditTime); stepLogger.logAuditExecutionResult(auditResult, executionStep.getLoadedTask()); - AfterExecutionAuditStep afterExecutionAudit = executionStep.applyAuditResult(auditResult); + AfterExecutionAuditStep afterExecutionAudit = executionStep.withAuditResult(auditResult); summarizer.add(afterExecutionAudit); return afterExecutionAudit; } diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/strategy/NonTxChangeProcessStrategy.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/strategy/NonTxChangeProcessStrategy.java index 9264835b0..31c8621dc 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/strategy/NonTxChangeProcessStrategy.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/strategy/NonTxChangeProcessStrategy.java @@ -22,11 +22,14 @@ import io.flamingock.internal.core.runtime.proxy.LockGuardProxyFactory; import io.flamingock.internal.core.targets.operations.TargetSystemOps; import io.flamingock.internal.core.task.executable.ExecutableTask; +import io.flamingock.internal.core.task.navigation.FailedChangeProcessResult; import io.flamingock.internal.core.task.navigation.navigator.AuditStoreStepOperations; +import io.flamingock.internal.core.task.navigation.navigator.ChangeProcessResult; import io.flamingock.internal.core.task.navigation.step.ExecutableStep; import io.flamingock.internal.core.task.navigation.step.RollableFailedStep; import io.flamingock.internal.core.task.navigation.step.StartStep; import io.flamingock.internal.core.task.navigation.step.afteraudit.AfterExecutionAuditStep; +import io.flamingock.internal.core.task.navigation.step.afteraudit.FailedAfterExecutionAuditStep; import io.flamingock.internal.core.task.navigation.step.execution.ExecutionStep; import io.flamingock.internal.core.task.navigation.step.rolledback.ManualRolledBackStep; import io.flamingock.internal.util.log.FlamingockLoggerFactory; @@ -83,7 +86,7 @@ public NonTxChangeProcessStrategy(ExecutableTask change, } @Override - protected TaskSummary doApplyChange() { + protected ChangeProcessResult doApplyChange() { StartStep startStep = new StartStep(change); ExecutableStep executableStep = auditAndLogStartExecution(startStep, executionContext); @@ -94,15 +97,19 @@ protected TaskSummary doApplyChange() { AfterExecutionAuditStep afterAudit = auditAndLogExecution(changeAppliedStep); - if (afterAudit instanceof RollableFailedStep) { - rollbackActualChangeAndChain((RollableFailedStep) afterAudit, executionContext); - return summarizer.setFailed().getSummary(); + + if(afterAudit instanceof FailedAfterExecutionAuditStep) { + FailedAfterExecutionAuditStep failedAfterExecutionAudit = (FailedAfterExecutionAuditStep)afterAudit; + rollbackActualChangeAndChain(failedAfterExecutionAudit, executionContext); + TaskSummary summary = summarizer.setFailed().getSummary(); + return new FailedChangeProcessResult(change.getId(), summary, failedAfterExecutionAudit.getMainError()); } else { - return summarizer.setSuccessful().getSummary(); + return new ChangeProcessResult(change.getId(), summarizer.setSuccessful().getSummary()); } + } - private void rollbackActualChangeAndChain(RollableFailedStep rollableFailedStep, ExecutionContext executionContext) { + private void rollbackActualChangeAndChain(FailedAfterExecutionAuditStep rollableFailedStep, ExecutionContext executionContext) { rollableFailedStep.getRollbackSteps().forEach(rollableStep -> { ManualRolledBackStep rolledBack = rollableStep.rollback(buildExecutionRuntime()); stepLogger.logManualRollbackResult(rolledBack); diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/strategy/SharedTxChangeProcessStrategy.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/strategy/SharedTxChangeProcessStrategy.java index ea7c027ed..032ac3f30 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/strategy/SharedTxChangeProcessStrategy.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/strategy/SharedTxChangeProcessStrategy.java @@ -22,11 +22,14 @@ import io.flamingock.internal.core.runtime.proxy.LockGuardProxyFactory; import io.flamingock.internal.core.targets.operations.TransactionalTargetSystemOps; import io.flamingock.internal.core.task.executable.ExecutableTask; +import io.flamingock.internal.core.task.navigation.FailedChangeProcessResult; import io.flamingock.internal.core.task.navigation.navigator.AuditStoreStepOperations; +import io.flamingock.internal.core.task.navigation.navigator.ChangeProcessResult; import io.flamingock.internal.core.task.navigation.step.ExecutableStep; import io.flamingock.internal.core.task.navigation.step.RollableFailedStep; import io.flamingock.internal.core.task.navigation.step.StartStep; import io.flamingock.internal.core.task.navigation.step.afteraudit.AfterExecutionAuditStep; +import io.flamingock.internal.core.task.navigation.step.afteraudit.FailedAfterExecutionAuditStep; import io.flamingock.internal.core.task.navigation.step.complete.CompletedSuccessStep; import io.flamingock.internal.core.task.navigation.step.complete.failed.CompleteAutoRolledBackStep; import io.flamingock.internal.core.task.navigation.step.execution.ExecutionStep; @@ -88,7 +91,7 @@ public SharedTxChangeProcessStrategy(ExecutableTask change, } @Override - protected TaskSummary doApplyChange() { + protected ChangeProcessResult doApplyChange() { logger.debug("Executing shared-transactional task [change={}]", change.getId()); Wrapper executionStep = new Wrapper<>(null); @@ -99,15 +102,18 @@ protected TaskSummary doApplyChange() { return auditAndLogExecution(executionStep.getValue()); }, buildExecutionRuntime()); - if(changeExecutionAndAudit instanceof CompletedSuccessStep) { - // Success: both change and audit committed atomically - return summarizer.setSuccessful().getSummary(); - } else { - // Failure: attempt detailed failure audit in separate transaction + if(changeExecutionAndAudit instanceof FailedAfterExecutionAuditStep) { + // Failure:this means nothing was persisted(all or nothing) auditIfExecutionFailure(executionStep); + Throwable mainError = ((FailedAfterExecutionAuditStep)changeExecutionAndAudit) + .getMainError(); rollbackChain((RollableFailedStep) changeExecutionAndAudit, executionContext); - return summarizer.setFailed().getSummary(); + return new FailedChangeProcessResult(change.getId(), summarizer.setFailed().getSummary(), mainError); + } else { + // Success: both change and audit committed atomically + return new ChangeProcessResult(change.getId(), summarizer.setSuccessful().getSummary()); } + } diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/strategy/SimpleTxChangeProcessStrategy.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/strategy/SimpleTxChangeProcessStrategy.java index 11d58cbc6..a44452661 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/strategy/SimpleTxChangeProcessStrategy.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/navigator/strategy/SimpleTxChangeProcessStrategy.java @@ -22,11 +22,14 @@ import io.flamingock.internal.core.runtime.proxy.LockGuardProxyFactory; import io.flamingock.internal.core.targets.operations.TransactionalTargetSystemOps; import io.flamingock.internal.core.task.executable.ExecutableTask; +import io.flamingock.internal.core.task.navigation.FailedChangeProcessResult; import io.flamingock.internal.core.task.navigation.navigator.AuditStoreStepOperations; +import io.flamingock.internal.core.task.navigation.navigator.ChangeProcessResult; import io.flamingock.internal.core.task.navigation.step.ExecutableStep; import io.flamingock.internal.core.task.navigation.step.RollableFailedStep; import io.flamingock.internal.core.task.navigation.step.StartStep; import io.flamingock.internal.core.task.navigation.step.afteraudit.AfterExecutionAuditStep; +import io.flamingock.internal.core.task.navigation.step.afteraudit.FailedAfterExecutionAuditStep; import io.flamingock.internal.core.task.navigation.step.complete.CompletedSuccessStep; import io.flamingock.internal.core.task.navigation.step.complete.failed.CompleteAutoRolledBackStep; import io.flamingock.internal.core.task.navigation.step.execution.ExecutionStep; @@ -91,7 +94,7 @@ public SimpleTxChangeProcessStrategy(ExecutableTask change, } @Override - protected TaskSummary doApplyChange() { + protected ChangeProcessResult doApplyChange() { logger.debug("Executing transactional task [change={}]", change.getId()); StartStep startStep = new StartStep(change); @@ -109,19 +112,24 @@ protected TaskSummary doApplyChange() { AfterExecutionAuditStep afterAudit = auditAndLogExecution(changeResult); if(changeResult.isSuccessStep()) { - if(afterAudit instanceof CompletedSuccessStep) { + if(afterAudit instanceof FailedAfterExecutionAuditStep) { + // Change applied but audit failed - leave marker for recovery + Throwable mainError = ((FailedAfterExecutionAuditStep)afterAudit) + .getMainError(); + return new FailedChangeProcessResult(change.getId(), summarizer.setFailed().getSummary(), mainError); + } else { // Success: change applied and audited, clear marker targetSystemOps.clearMark(change.getId()); - return summarizer.setSuccessful().getSummary(); - } else { - // Change applied but audit failed - leave marker for recovery - return summarizer.setFailed().getSummary(); + return new ChangeProcessResult(change.getId(), summarizer.setSuccessful().getSummary()); } + } else { // Change execution failed - transaction automatically rolled back + Throwable mainError = ((FailedAfterExecutionAuditStep)afterAudit) + .getMainError(); auditAndLogAutoRollback(); rollbackChain((RollableFailedStep) afterAudit, executionContext); - return summarizer.setFailed().getSummary(); + return new FailedChangeProcessResult(change.getId(), summarizer.setFailed().getSummary(), mainError); } } diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/ExecutableStep.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/ExecutableStep.java index e0df49b89..12eb0f283 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/ExecutableStep.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/ExecutableStep.java @@ -17,7 +17,7 @@ import io.flamingock.internal.core.task.navigation.step.execution.ExecutionStep; import io.flamingock.internal.core.task.navigation.step.execution.FailedExecutionStep; -import io.flamingock.internal.core.task.navigation.step.execution.SuccessExecutionStep; +import io.flamingock.internal.core.task.navigation.step.execution.SuccessApplyStep; import io.flamingock.internal.core.runtime.ExecutionRuntime; import io.flamingock.internal.util.StopWatch; @@ -31,7 +31,7 @@ public ExecutionStep execute(ExecutionRuntime executionRuntime) { StopWatch stopWatch = StopWatch.startAndGet(); try { task.execute(executionRuntime); - return SuccessExecutionStep.instance(this, stopWatch.getElapsed()); + return SuccessApplyStep.instance(this, stopWatch.getElapsed()); } catch (Throwable throwable) { return FailedExecutionStep.instance(this, stopWatch.getElapsed(), throwable); } diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/FailedWithErrorStep.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/FailedWithErrorStep.java index d37cf937c..f467ad02b 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/FailedWithErrorStep.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/FailedWithErrorStep.java @@ -16,5 +16,5 @@ package io.flamingock.internal.core.task.navigation.step; public interface FailedWithErrorStep extends FailedStep { - Throwable getError(); + Throwable getMainError(); } diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/afteraudit/FailedAfterExecutionAuditStep.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/afteraudit/FailedAfterExecutionAuditStep.java index caa2f4ac6..7e986c853 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/afteraudit/FailedAfterExecutionAuditStep.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/afteraudit/FailedAfterExecutionAuditStep.java @@ -15,6 +15,7 @@ */ package io.flamingock.internal.core.task.navigation.step.afteraudit; +import io.flamingock.internal.core.task.navigation.step.FailedWithErrorStep; import io.flamingock.internal.core.task.navigation.step.RollableFailedStep; import io.flamingock.internal.core.task.navigation.step.SuccessableStep; import io.flamingock.internal.core.task.executable.ExecutableTask; @@ -24,23 +25,26 @@ import java.util.stream.Collectors; public abstract class FailedAfterExecutionAuditStep extends AfterExecutionAuditStep - implements SuccessableStep, RollableFailedStep { + implements SuccessableStep, RollableFailedStep, FailedWithErrorStep { - - public static FailedAfterExecutionAuditStep instance(ExecutableTask task, Result auditResult) { + public static FailedAfterExecutionAuditStep fromFailedApply(ExecutableTask task, Throwable errorOnApply, Result auditResult) { if (auditResult instanceof Result.Error) { Result.Error errorResult = (Result.Error) auditResult; - return new FailedAuditExecutionStep(task, errorResult.getError()); + return new FailedExecutionFailedAuditStep(task, errorOnApply, errorResult.getError()); } else { - return new FailedExecutionSuccessAuditStep(task); + return new FailedExecutionSuccessAuditStep(task, errorOnApply); } } - protected FailedAfterExecutionAuditStep(ExecutableTask task, boolean successExecutionAudit) { - super(task, successExecutionAudit); + public static FailedAfterExecutionAuditStep fromSuccessApply(ExecutableTask task, Result.Error errorOnAudit) { + return new SuccessExecutionFailedAuditStep(task, errorOnAudit.getError()); } + protected FailedAfterExecutionAuditStep(ExecutableTask task, boolean successAuditOperation) { + super(task, successAuditOperation); + } + @Override public final List getRollbackSteps() { return task.getRollbackChain() diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/afteraudit/FailedExecutionFailedAuditStep.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/afteraudit/FailedExecutionFailedAuditStep.java new file mode 100644 index 000000000..cefaf8da1 --- /dev/null +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/afteraudit/FailedExecutionFailedAuditStep.java @@ -0,0 +1,46 @@ +/* + * Copyright 2023 Flamingock (https://www.flamingock.io) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.flamingock.internal.core.task.navigation.step.afteraudit; + +import io.flamingock.internal.core.task.executable.ExecutableTask; +import io.flamingock.internal.core.task.navigation.step.FailedWithErrorStep; + +public final class FailedExecutionFailedAuditStep extends FailedAfterExecutionAuditStep { + + private final Throwable errorOnApply; + private final Throwable errorOnAudit; + + FailedExecutionFailedAuditStep(ExecutableTask task, + Throwable errorOnApply, + Throwable errorOnAudit) { + super(task, true); + this.errorOnApply = errorOnApply; + this.errorOnAudit = errorOnAudit; + } + + public Throwable getErrorOnApply() { + return errorOnApply; + } + + public Throwable getErrorOnAudit() { + return getMainError(); + } + + @Override + public Throwable getMainError() { + return getErrorOnApply(); + } +} diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/afteraudit/FailedExecutionSuccessAuditStep.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/afteraudit/FailedExecutionSuccessAuditStep.java index 3dc74fec4..8af2843f1 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/afteraudit/FailedExecutionSuccessAuditStep.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/afteraudit/FailedExecutionSuccessAuditStep.java @@ -18,7 +18,19 @@ import io.flamingock.internal.core.task.executable.ExecutableTask; public final class FailedExecutionSuccessAuditStep extends FailedAfterExecutionAuditStep { - FailedExecutionSuccessAuditStep(ExecutableTask task) { + private final Throwable errorOnApply; + + FailedExecutionSuccessAuditStep(ExecutableTask task, Throwable errorOnApply) { super(task, true); + this.errorOnApply = errorOnApply; + } + + public Throwable getErrorOnApply() { + return errorOnApply; + } + + @Override + public Throwable getMainError() { + return getErrorOnApply(); } } diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/afteraudit/FailedAuditExecutionStep.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/afteraudit/SuccessExecutionFailedAuditStep.java similarity index 67% rename from core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/afteraudit/FailedAuditExecutionStep.java rename to core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/afteraudit/SuccessExecutionFailedAuditStep.java index 4b1e3e442..7f38e012d 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/afteraudit/FailedAuditExecutionStep.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/afteraudit/SuccessExecutionFailedAuditStep.java @@ -15,22 +15,25 @@ */ package io.flamingock.internal.core.task.navigation.step.afteraudit; -import io.flamingock.internal.core.task.navigation.step.FailedWithErrorStep; import io.flamingock.internal.core.task.executable.ExecutableTask; +import io.flamingock.internal.core.task.navigation.step.FailedWithErrorStep; -public final class FailedAuditExecutionStep extends FailedAfterExecutionAuditStep implements FailedWithErrorStep { +public final class SuccessExecutionFailedAuditStep extends FailedAfterExecutionAuditStep +implements FailedWithErrorStep { - private final Throwable error; + private final Throwable errorOnAudit; - FailedAuditExecutionStep(ExecutableTask task, Throwable error) { + SuccessExecutionFailedAuditStep(ExecutableTask task, Throwable errorOnAudit) { super(task, false); - this.error = error; + this.errorOnAudit = errorOnAudit; } - @Override - public Throwable getError() { - return error; + public Throwable getErrorOnAudit() { + return errorOnAudit; } - + @Override + public Throwable getMainError() { + return getErrorOnAudit(); + } } diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/complete/CompletedSuccessStep.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/complete/CompletedSuccessStep.java index c2f6b99fd..460a0d7ee 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/complete/CompletedSuccessStep.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/complete/CompletedSuccessStep.java @@ -16,12 +16,12 @@ package io.flamingock.internal.core.task.navigation.step.complete; import io.flamingock.internal.core.task.navigation.step.afteraudit.AfterExecutionAuditStep; -import io.flamingock.internal.core.task.navigation.step.execution.SuccessExecutionStep; +import io.flamingock.internal.core.task.navigation.step.execution.SuccessApplyStep; import io.flamingock.internal.core.task.executable.ExecutableTask; public final class CompletedSuccessStep extends AfterExecutionAuditStep { - public static CompletedSuccessStep fromSuccessExecution(SuccessExecutionStep appliedStep) { + public static CompletedSuccessStep fromSuccessExecution(SuccessApplyStep appliedStep) { return new CompletedSuccessStep(appliedStep.getTask()); } diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/complete/failed/CompletedFailedAtRollbackAuditStep.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/complete/failed/CompletedFailedAtRollbackAuditStep.java index 009196c3e..4bd102a8b 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/complete/failed/CompletedFailedAtRollbackAuditStep.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/complete/failed/CompletedFailedAtRollbackAuditStep.java @@ -28,7 +28,7 @@ public final class CompletedFailedAtRollbackAuditStep extends CompletedFailedMan } @Override - public Throwable getError() { + public Throwable getMainError() { return errorAtRollbackAudit; } diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/execution/ExecutionStep.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/execution/ExecutionStep.java index 35af2ee44..2f4150b04 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/execution/ExecutionStep.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/execution/ExecutionStep.java @@ -32,12 +32,11 @@ protected ExecutionStep(ExecutableTask task, boolean successExecution, long dura this.duration = duration; } - public long getDuration() { return duration; } - public abstract AfterExecutionAuditStep applyAuditResult(Result saveResult); + public abstract AfterExecutionAuditStep withAuditResult(Result saveResult); @Override public final boolean isSuccessStep() { diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/execution/FailedExecutionStep.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/execution/FailedExecutionStep.java index 09dc1f703..3f38d2db8 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/execution/FailedExecutionStep.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/execution/FailedExecutionStep.java @@ -17,31 +17,31 @@ import io.flamingock.internal.core.task.navigation.step.ExecutableStep; import io.flamingock.internal.core.task.navigation.step.FailedWithErrorStep; -import io.flamingock.internal.core.task.navigation.step.afteraudit.AfterExecutionAuditStep; import io.flamingock.internal.core.task.navigation.step.afteraudit.FailedAfterExecutionAuditStep; import io.flamingock.internal.core.task.executable.ExecutableTask; import io.flamingock.internal.util.Result; public final class FailedExecutionStep extends ExecutionStep implements FailedWithErrorStep { - private final Throwable throwable; public static FailedExecutionStep instance(ExecutableStep initialStep, long executionTimeMillis, Throwable throwable) { return new FailedExecutionStep(initialStep.getTask(), executionTimeMillis, throwable); } - private FailedExecutionStep(ExecutableTask task, long executionTimeMillis, Throwable throwable) { + private final Throwable errorOnApply; + + private FailedExecutionStep(ExecutableTask task, long executionTimeMillis, Throwable errorOnApply) { super(task, false, executionTimeMillis); - this.throwable = throwable; + this.errorOnApply = errorOnApply; } @Override - public Throwable getError() { - return throwable; + public Throwable getMainError() { + return errorOnApply; } @Override - public AfterExecutionAuditStep applyAuditResult(Result auditResult) { - return FailedAfterExecutionAuditStep.instance(task, auditResult); + public FailedAfterExecutionAuditStep withAuditResult(Result auditResult) { + return FailedAfterExecutionAuditStep.fromFailedApply(task, errorOnApply, auditResult); } } diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/execution/SuccessExecutionStep.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/execution/SuccessApplyStep.java similarity index 67% rename from core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/execution/SuccessExecutionStep.java rename to core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/execution/SuccessApplyStep.java index 11de273dc..e4ade09d2 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/execution/SuccessExecutionStep.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/execution/SuccessApplyStep.java @@ -15,26 +15,26 @@ */ package io.flamingock.internal.core.task.navigation.step.execution; +import io.flamingock.internal.core.task.executable.ExecutableTask; import io.flamingock.internal.core.task.navigation.step.ExecutableStep; import io.flamingock.internal.core.task.navigation.step.afteraudit.AfterExecutionAuditStep; import io.flamingock.internal.core.task.navigation.step.afteraudit.FailedAfterExecutionAuditStep; import io.flamingock.internal.core.task.navigation.step.complete.CompletedSuccessStep; -import io.flamingock.internal.core.task.executable.ExecutableTask; import io.flamingock.internal.util.Result; -public final class SuccessExecutionStep extends ExecutionStep { - public static SuccessExecutionStep instance(ExecutableStep initialStep, long executionTimeMillis) { - return new SuccessExecutionStep(initialStep.getTask(), executionTimeMillis); +public final class SuccessApplyStep extends ExecutionStep { + public static SuccessApplyStep instance(ExecutableStep initialStep, long executionTimeMillis) { + return new SuccessApplyStep(initialStep.getTask(), executionTimeMillis); } - private SuccessExecutionStep(ExecutableTask task, long executionTimeMillis) { + private SuccessApplyStep(ExecutableTask task, long executionTimeMillis) { super(task, true, executionTimeMillis); } @Override - public AfterExecutionAuditStep applyAuditResult(Result auditResult) { - return auditResult.isOk() - ? CompletedSuccessStep.fromSuccessExecution(this) - : FailedAfterExecutionAuditStep.instance(task, auditResult); + public AfterExecutionAuditStep withAuditResult(Result auditResult) { + return auditResult.isError() + ? FailedAfterExecutionAuditStep.fromSuccessApply(task, (Result.Error) auditResult) + : CompletedSuccessStep.fromSuccessExecution(this); } } diff --git a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/rolledback/FailedManualRolledBackStep.java b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/rolledback/FailedManualRolledBackStep.java index a3d884b39..865f1d7e2 100644 --- a/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/rolledback/FailedManualRolledBackStep.java +++ b/core/flamingock-core/src/main/java/io/flamingock/internal/core/task/navigation/step/rolledback/FailedManualRolledBackStep.java @@ -29,7 +29,7 @@ public final class FailedManualRolledBackStep extends ManualRolledBackStep imple } @Override - public Throwable getError() { + public Throwable getMainError() { return error; } diff --git a/core/target-systems/dynamodb-target-system/src/main/java/io/flamingock/targetsystem/dynamodb/DynamoDBTxWrapper.java b/core/target-systems/dynamodb-target-system/src/main/java/io/flamingock/targetsystem/dynamodb/DynamoDBTxWrapper.java index b78dbd907..716ad8814 100644 --- a/core/target-systems/dynamodb-target-system/src/main/java/io/flamingock/targetsystem/dynamodb/DynamoDBTxWrapper.java +++ b/core/target-systems/dynamodb-target-system/src/main/java/io/flamingock/targetsystem/dynamodb/DynamoDBTxWrapper.java @@ -81,7 +81,7 @@ public T wrapInTransaction(ExecutionRuntime executionRuntime, Function String.format("%s: %s", reason.code(), reason.message())) .collect(Collectors.joining(", ")); - logger.error("DynamoDB transaction cancelled [duration={} reasons={}]", + logger.debug("DynamoDB transaction cancelled [duration={} reasons={}]", formatDuration(transactionDuration), cancellationReasons); throw new DatabaseTransactionException( @@ -96,7 +96,7 @@ public T wrapInTransaction(ExecutionRuntime executionRuntime, Function T wrapInTransaction(ExecutionRuntime executionRuntime, Function T wrapInTransaction(ExecutionRuntime executionRuntime, Function T wrapInTransaction(ExecutionRuntime executionRuntime, Function T wrapInTransaction(ExecutionRuntime executionRuntime, Function T wrapInTransaction(ExecutionRuntime executionRuntime, Function T wrapInTransaction(ExecutionRuntime executionRuntime, Function errorInfo = new LinkedHashMap<>(); + errorInfo.put("type", e.getClass().getName()); + errorInfo.put("message", Objects.toString(e.getMessage(), "")); + + Throwable root = getRootCause(e); + if (root != null && root != e) { + Map rootInfo = new LinkedHashMap<>(); + rootInfo.put("type", root.getClass().getName()); + rootInfo.put("message", Objects.toString(root.getMessage(), "")); + errorInfo.put("rootCause", rootInfo); + } + + List> frames = Arrays.stream(e.getStackTrace()) + .limit(maxFrames) + .map(frame -> { + Map f = new LinkedHashMap<>(); + f.put("className", frame.getClassName()); + f.put("methodName", frame.getMethodName()); + f.put("fileName", frame.getFileName()); + f.put("lineNumber", frame.getLineNumber()); + return f; + }) + .collect(Collectors.toList()); + + errorInfo.put("stackTrace", frames); + + try { + String json = MAPPER.writeValueAsString(errorInfo); + if (json.length() > MAX_CHARS) { + return json.substring(0, MAX_CHARS) + "..."; + } + return json; + } catch (Exception ex) { + return "{\"type\":\"" + e.getClass().getName() + "\",\"serializationError\":\"" + ex.getMessage() + "\"}"; + } + } + + private static Throwable getRootCause(Throwable e) { + Throwable cause = e.getCause(); + if (cause == null) return null; + while (cause.getCause() != null) { + cause = cause.getCause(); + } + return cause; } }