This is an automated email from the ASF dual-hosted git repository. danhaywood pushed a commit to branch CAUSEWAY-3799 in repository https://gitbox.apache.org/repos/asf/causeway.git
commit 5c2764a9bd741f219f7b8224ffae59c8ea272ada Author: Dan Haywood <[email protected]> AuthorDate: Fri Jun 28 14:41:14 2024 +0100 CAUSEWAY-3799: reduces duplicate logging in CausewayInteraction if a deadlock has been hit --- .../interaction/session/CausewayInteraction.java | 51 ++++++++++++---------- .../metamodel/execution/InteractionInternal.java | 23 +++++----- .../executor/MemberExecutorServiceDefault.java | 9 ++-- 3 files changed, 47 insertions(+), 36 deletions(-) diff --git a/core/interaction/src/main/java/org/apache/causeway/core/interaction/session/CausewayInteraction.java b/core/interaction/src/main/java/org/apache/causeway/core/interaction/session/CausewayInteraction.java index 8d23f8ce17..614a4d9b73 100644 --- a/core/interaction/src/main/java/org/apache/causeway/core/interaction/session/CausewayInteraction.java +++ b/core/interaction/src/main/java/org/apache/causeway/core/interaction/session/CausewayInteraction.java @@ -36,7 +36,6 @@ import org.apache.causeway.commons.internal.base._Casts; import org.apache.causeway.commons.internal.collections._Lists; import org.apache.causeway.commons.internal.exceptions._Exceptions; import org.apache.causeway.core.metamodel.execution.InteractionInternal; -import org.apache.causeway.core.metamodel.services.publishing.CommandPublisher; import lombok.Getter; import lombok.NonNull; @@ -51,7 +50,9 @@ implements InteractionInternal { public CausewayInteraction(final @NonNull UUID interactionId) { this.startedAtSystemNanos = System.nanoTime(); // used to measure time periods, so not using ClockService here this.command = new Command(interactionId); - log.debug("new CausewayInteraction id={}", interactionId); + if(log.isDebugEnabled()) { + log.debug("new CausewayInteraction id={}", interactionId); + } } @Getter(onMethod_ = {@Override}) @@ -98,16 +99,14 @@ implements InteractionInternal { public Object execute( final MemberExecutor<ActionInvocation> memberExecutor, final ActionInvocation actionInvocation, - final ClockService clockService, - final MetricsService metricsService, - final CommandPublisher commandPublisher) { + final Context context) { push(actionInvocation); - start(actionInvocation, clockService, metricsService, commandPublisher); + start(actionInvocation, context); try { - return executeInternal(memberExecutor, actionInvocation); + return executeInternal(memberExecutor, actionInvocation, context); } finally { - popAndComplete(clockService, metricsService); + popAndComplete(context.getClockService(), context.getMetricsService()); } } @@ -115,21 +114,21 @@ implements InteractionInternal { public Object execute( final MemberExecutor<PropertyEdit> memberExecutor, final PropertyEdit propertyEdit, - final ClockService clockService, - final MetricsService metricsService, - final CommandPublisher commandPublisher, - final Command command) { + final Context context) { push(propertyEdit); - start(propertyEdit, clockService, metricsService, commandPublisher); + start(propertyEdit, context); try { - return executeInternal(memberExecutor, propertyEdit); + return executeInternal(memberExecutor, propertyEdit, context); } finally { - popAndComplete(clockService, metricsService); + popAndComplete(context.getClockService(), context.getMetricsService()); } } - private <T extends Execution<?,?>> Object executeInternal(final MemberExecutor<T> memberExecutor, final T execution) { + private <T extends Execution<?,?>> Object executeInternal( + final MemberExecutor<T> memberExecutor, + final T execution, + final Context context) { try { Object result = memberExecutor.execute(execution); @@ -142,7 +141,17 @@ implements InteractionInternal { // examples are IllegalArgument- or NullPointer- exceptions being swallowed when using the // WrapperFactory utilizing async calls - log.error("failed to execute an interaction", _Exceptions.getRootCause(ex).orElse(null)); + if(context.getDeadlockRecognizer().isDeadlock(ex)) { + if(log.isDebugEnabled()) { + log.debug("failed to execute an interaction due to a deadlock", ex); + } else if(log.isInfoEnabled()) { + log.info("failed to execute an interaction due to a deadlock"); + } + } else { + if(log.isErrorEnabled()) { + log.error("failed to execute an interaction", _Exceptions.getRootCause(ex).orElse(null)); + } + } // just because an exception has thrown, does not mean it is that significant; // it could be that it is recognized by an ExceptionRecognizer and is not severe @@ -183,18 +192,16 @@ implements InteractionInternal { private void start( final Execution<?,?> execution, - final ClockService clockService, - final MetricsService metricsService, - final CommandPublisher commandPublisher) { + final Context context) { // set the startedAt (and update command if this is the top-most member execution) // (this isn't done within Interaction#execute(...) because it requires the DTO // to have been set on the current execution). - val startedAt = execution.start(clockService, metricsService); + val startedAt = execution.start(context.getClockService(), context.getMetricsService()); if(getCommand().getStartedAt() == null) { getCommand().updater().setStartedAt(startedAt); getCommand().updater().setPublishingPhase(Command.CommandPublishingPhase.STARTED); } - commandPublisher.start(getCommand()); + context.getCommandPublisher().start(getCommand()); } /** diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/execution/InteractionInternal.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/execution/InteractionInternal.java index 500421f62f..4638e3c09f 100644 --- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/execution/InteractionInternal.java +++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/execution/InteractionInternal.java @@ -22,16 +22,17 @@ import java.util.concurrent.Callable; import java.util.concurrent.atomic.LongAdder; import org.apache.causeway.applib.services.clock.ClockService; -import org.apache.causeway.applib.services.command.Command; import org.apache.causeway.applib.services.iactn.ActionInvocation; import org.apache.causeway.applib.services.iactn.Execution; import org.apache.causeway.applib.services.iactn.Interaction; import org.apache.causeway.applib.services.iactn.PropertyEdit; import org.apache.causeway.applib.services.metrics.MetricsService; import org.apache.causeway.applib.services.wrapper.WrapperFactory; +import org.apache.causeway.core.metamodel.services.deadlock.DeadlockRecognizer; import org.apache.causeway.core.metamodel.services.publishing.CommandPublisher; import lombok.NonNull; +import lombok.Value; import lombok.val; /** @@ -44,13 +45,18 @@ extends Interaction { * (Modeled after {@link Callable}), is the implementation * by which the framework actually performs the interaction. */ - public interface MemberExecutor<T extends Execution<?,?>> { + interface MemberExecutor<T extends Execution<?,?>> { Object execute(final T currentExecution); } - static class Context { - + @Value(staticConstructor = "of") + class Context { + ClockService clockService; + MetricsService metricsService; + CommandPublisher commandPublisher; + DeadlockRecognizer deadlockRecognizer; } + /** * Use the provided {@link MemberExecutor} to invoke an action, with the provided * {@link ActionInvocation} capturing @@ -63,9 +69,7 @@ extends Interaction { Object execute( final MemberExecutor<ActionInvocation> memberExecutor, final ActionInvocation actionInvocation, - final ClockService clockService, - final MetricsService metricsService, - final CommandPublisher commandPublisher); + final Context context); /** * Use the provided {@link MemberExecutor} to edit a property, with the provided @@ -79,10 +83,7 @@ extends Interaction { Object execute( final MemberExecutor<PropertyEdit> memberExecutor, final PropertyEdit propertyEdit, - final ClockService clockService, - final MetricsService metricsService, - final CommandPublisher commandPublisher, - final Command command); + final Context context); /** diff --git a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/executor/MemberExecutorServiceDefault.java b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/executor/MemberExecutorServiceDefault.java index 761d5b1976..b76e164fb2 100644 --- a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/executor/MemberExecutorServiceDefault.java +++ b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/executor/MemberExecutorServiceDefault.java @@ -25,6 +25,8 @@ import javax.inject.Inject; import javax.inject.Named; import javax.inject.Provider; +import org.apache.causeway.core.metamodel.services.deadlock.DeadlockRecognizer; + import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; @@ -96,6 +98,7 @@ implements MemberExecutorService { private final @Getter CausewayConfiguration configuration; private final @Getter ObjectManager objectManager; private final @Getter ClockService clockService; + private final @Getter DeadlockRecognizer deadlockRecognizer; private final @Getter ServiceInjector serviceInjector; private final @Getter Provider<MetricsService> metricsServiceProvider; private final @Getter InteractionDtoFactory interactionDtoFactory; @@ -169,7 +172,7 @@ implements MemberExecutorService { interaction, actionId, targetPojo, argumentPojos); // sets up startedAt and completedAt on the execution, also manages the execution call graph - interaction.execute(actionExecutor, actionInvocation, clockService, metricsService(), commandPublisherProvider.get()); + interaction.execute(actionExecutor, actionInvocation, InteractionInternal.Context.of(clockService, metricsService(), commandPublisherProvider.get(), deadlockRecognizer)); // handle any exceptions val priorExecution = interaction.getPriorExecutionOrThrowIfAnyException(actionInvocation); @@ -266,8 +269,8 @@ implements MemberExecutorService { val propertyEdit = new PropertyEdit(interaction, propertyId, target, argValuePojo); // sets up startedAt and completedAt on the execution, also manages the execution call graph - val targetPojo = interaction.execute(propertyModifier, propertyEdit, clockService, metricsService(), - commandPublisherProvider.get(), command); + val targetPojo = interaction.execute(propertyModifier, propertyEdit, + InteractionInternal.Context.of(clockService, metricsService(), commandPublisherProvider.get(), deadlockRecognizer)); // handle any exceptions final Execution<?, ?> priorExecution = interaction.getPriorExecution();
