From 21136968ce02f1e827bc7e7e1902e30e333e864d Mon Sep 17 00:00:00 2001 From: Colt McNealy Date: Wed, 19 Feb 2025 12:06:34 -0800 Subject: [PATCH] fix(server): external-event timeout (#1313) - #665 introduced a bug which prevented an ExternalEvent timeout from throwing a NodeFailureException. --- .../subnoderun/ExternalEventNodeRunModel.java | 9 +++++-- .../src/test/java/e2e/ExternalEventTest.java | 24 +++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/io/littlehorse/common/model/getable/core/wfrun/subnoderun/ExternalEventNodeRunModel.java b/server/src/main/java/io/littlehorse/common/model/getable/core/wfrun/subnoderun/ExternalEventNodeRunModel.java index 8d09baa75..dd5ffd85d 100644 --- a/server/src/main/java/io/littlehorse/common/model/getable/core/wfrun/subnoderun/ExternalEventNodeRunModel.java +++ b/server/src/main/java/io/littlehorse/common/model/getable/core/wfrun/subnoderun/ExternalEventNodeRunModel.java @@ -18,6 +18,7 @@ import io.littlehorse.common.model.getable.objectId.ExternalEventIdModel; import io.littlehorse.common.util.LHUtil; import io.littlehorse.sdk.common.proto.ExternalEventNodeRun; +import io.littlehorse.sdk.common.proto.LHErrorType; import io.littlehorse.sdk.common.proto.LHStatus; import io.littlehorse.sdk.common.proto.VariableType; import io.littlehorse.server.streams.topology.core.ExecutionContext; @@ -84,9 +85,14 @@ public ExternalEventNodeRun.Builder toProto() { } @Override - public boolean checkIfProcessingCompleted(ProcessorExecutionContext processorContext) { + public boolean checkIfProcessingCompleted(ProcessorExecutionContext processorContext) throws NodeFailureException { if (externalEventId != null) return true; + if (timedOut) { + FailureModel failure = new FailureModel("ExternalEvent did not arrive in time", LHErrorType.TIMEOUT.name()); + throw new NodeFailureException(failure); + } + NodeModel node = nodeRun.getNode(); ExternalEventNodeModel eNode = node.getExternalEventNode(); @@ -165,7 +171,6 @@ public void processExternalEventTimeout(ExternalEventTimeoutModel timeout) { return; } - // This is leaking the logic of the timedOut = true; } diff --git a/server/src/test/java/e2e/ExternalEventTest.java b/server/src/test/java/e2e/ExternalEventTest.java index 4438db8fc..11f039db6 100644 --- a/server/src/test/java/e2e/ExternalEventTest.java +++ b/server/src/test/java/e2e/ExternalEventTest.java @@ -5,6 +5,8 @@ import io.littlehorse.sdk.common.proto.ExternalEvent; import io.littlehorse.sdk.common.proto.ExternalEventDefId; import io.littlehorse.sdk.common.proto.ExternalEventId; +import io.littlehorse.sdk.common.proto.Failure; +import io.littlehorse.sdk.common.proto.LHErrorType; import io.littlehorse.sdk.common.proto.LHStatus; import io.littlehorse.sdk.common.proto.LittleHorseGrpc.LittleHorseBlockingStub; import io.littlehorse.sdk.common.proto.PutExternalEventRequest; @@ -26,6 +28,9 @@ public class ExternalEventTest { public static final String EVT_NAME = "basic-test-event"; public static final String IGNORED_EVT_NAME = "not-a-real-event-kenobi"; + @LHWorkflow("external-event-timeout") + public Workflow timeoutEvent; + @LHWorkflow("basic-external-event") public Workflow basicExternalEvent; @@ -41,6 +46,25 @@ public Workflow getBasicExternalEventWorkflow() { }); } + @LHWorkflow("external-event-timeout") + public Workflow getTimeoutWorkflow() { + return Workflow.newWorkflow("external-event-timeout", wf -> { + wf.waitForEvent(EVT_NAME).timeout(1); + }); + } + + @Test + void shouldTimeoutIfNoEvent() { + verifier.prepareRun(timeoutEvent) + .waitForStatus(LHStatus.ERROR) + .thenVerifyNodeRun(0, 1, nodeRun -> { + Failure failure = nodeRun.getFailures(0); + Assertions.assertThat(failure.getFailureName()).isEqualTo(LHErrorType.TIMEOUT.toString()); + Assertions.assertThat(failure.getMessage().toLowerCase()).contains("arrive in time"); + }) + .start(); + } + @Test void shouldCompleteIfEventIsSentAfterWfRunStarts() { WfRunId id = WfRunId.newBuilder().setId(LHUtil.generateGuid()).build();