mirror of https://github.com/dapr/java-sdk.git
Adding examples to Spring Boot (duration, zoneddatetime and suspend/resume) (#1413)
* implementing createtime with zoneddatetime Signed-off-by: salaboy <Salaboy@gmail.com> * adding duration and zoneddatetime examples Signed-off-by: salaboy <Salaboy@gmail.com> * using external event wf to test suspend resume Signed-off-by: salaboy <Salaboy@gmail.com> --------- Signed-off-by: salaboy <Salaboy@gmail.com> Signed-off-by: sirivarma <siri.varma@outlook.com>
This commit is contained in:
parent
982b2874fe
commit
85f82f2e54
|
|
@ -14,23 +14,19 @@ limitations under the License.
|
||||||
package io.dapr.workflows;
|
package io.dapr.workflows;
|
||||||
|
|
||||||
import io.dapr.durabletask.CompositeTaskFailedException;
|
import io.dapr.durabletask.CompositeTaskFailedException;
|
||||||
import io.dapr.durabletask.FailureDetails;
|
|
||||||
import io.dapr.durabletask.RetryContext;
|
import io.dapr.durabletask.RetryContext;
|
||||||
import io.dapr.durabletask.RetryHandler;
|
import io.dapr.durabletask.RetryHandler;
|
||||||
import io.dapr.durabletask.Task;
|
import io.dapr.durabletask.Task;
|
||||||
import io.dapr.durabletask.TaskCanceledException;
|
import io.dapr.durabletask.TaskCanceledException;
|
||||||
import io.dapr.durabletask.TaskOptions;
|
import io.dapr.durabletask.TaskOptions;
|
||||||
import io.dapr.durabletask.TaskOrchestrationContext;
|
import io.dapr.durabletask.TaskOrchestrationContext;
|
||||||
|
|
||||||
import io.dapr.workflows.runtime.DefaultWorkflowContext;
|
import io.dapr.workflows.runtime.DefaultWorkflowContext;
|
||||||
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,8 @@ import io.dapr.springboot.examples.wfp.fanoutin.FanOutInWorkflow;
|
||||||
import io.dapr.springboot.examples.wfp.fanoutin.Result;
|
import io.dapr.springboot.examples.wfp.fanoutin.Result;
|
||||||
import io.dapr.springboot.examples.wfp.remoteendpoint.Payload;
|
import io.dapr.springboot.examples.wfp.remoteendpoint.Payload;
|
||||||
import io.dapr.springboot.examples.wfp.remoteendpoint.RemoteEndpointWorkflow;
|
import io.dapr.springboot.examples.wfp.remoteendpoint.RemoteEndpointWorkflow;
|
||||||
import io.dapr.springboot.examples.wfp.suspendresume.SuspendResumeWorkflow;
|
import io.dapr.springboot.examples.wfp.timer.DurationTimerWorkflow;
|
||||||
|
import io.dapr.springboot.examples.wfp.timer.ZonedDateTimeTimerWorkflow;
|
||||||
import io.dapr.workflows.client.DaprWorkflowClient;
|
import io.dapr.workflows.client.DaprWorkflowClient;
|
||||||
import io.dapr.workflows.client.WorkflowInstanceStatus;
|
import io.dapr.workflows.client.WorkflowInstanceStatus;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
@ -156,7 +157,7 @@ public class WorkflowPatternsRestController {
|
||||||
|
|
||||||
@PostMapping("wfp/suspendresume")
|
@PostMapping("wfp/suspendresume")
|
||||||
public String suspendResume(@RequestParam("orderId") String orderId) {
|
public String suspendResume(@RequestParam("orderId") String orderId) {
|
||||||
String instanceId = daprWorkflowClient.scheduleNewWorkflow(SuspendResumeWorkflow.class);
|
String instanceId = daprWorkflowClient.scheduleNewWorkflow(ExternalEventWorkflow.class);
|
||||||
logger.info("Workflow instance " + instanceId + " started");
|
logger.info("Workflow instance " + instanceId + " started");
|
||||||
ordersToApprove.put(orderId, instanceId);
|
ordersToApprove.put(orderId, instanceId);
|
||||||
return instanceId;
|
return instanceId;
|
||||||
|
|
@ -189,4 +190,16 @@ public class WorkflowPatternsRestController {
|
||||||
.waitForInstanceCompletion(instanceId, null, true);
|
.waitForInstanceCompletion(instanceId, null, true);
|
||||||
return workflowInstanceStatus.readOutputAs(Decision.class);
|
return workflowInstanceStatus.readOutputAs(Decision.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("wfp/durationtimer")
|
||||||
|
public String durationTimerWorkflow() {
|
||||||
|
return daprWorkflowClient.scheduleNewWorkflow(DurationTimerWorkflow.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("wfp/zoneddatetimetimer")
|
||||||
|
public String zonedDateTimeTimerWorkflow() {
|
||||||
|
return daprWorkflowClient.scheduleNewWorkflow(ZonedDateTimeTimerWorkflow.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2025 The Dapr Authors
|
||||||
|
* 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.dapr.springboot.examples.wfp.timer;
|
||||||
|
|
||||||
|
import io.dapr.workflows.Workflow;
|
||||||
|
import io.dapr.workflows.WorkflowStub;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class DurationTimerWorkflow implements Workflow {
|
||||||
|
@Override
|
||||||
|
public WorkflowStub create() {
|
||||||
|
return ctx -> {
|
||||||
|
ctx.getLogger().info("Starting Workflow: {}, instanceId: {}", ctx.getName(), ctx.getInstanceId());
|
||||||
|
|
||||||
|
ctx.getLogger().info("Let's call the first LogActivity at {}", new Date());
|
||||||
|
ctx.callActivity(LogActivity.class.getName()).await();
|
||||||
|
|
||||||
|
ctx.getLogger().info("Let's schedule a 10 seconds timer at {}", new Date());
|
||||||
|
ctx.createTimer(Duration.ofSeconds(10)).await();
|
||||||
|
|
||||||
|
ctx.getLogger().info("Let's call the second LogActivity at {}", new Date());
|
||||||
|
ctx.callActivity(LogActivity.class.getName()).await();
|
||||||
|
|
||||||
|
ctx.complete(true);
|
||||||
|
ctx.getLogger().info("Workflow completed at {}", new Date());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2025 The Dapr Authors
|
||||||
|
* 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.dapr.springboot.examples.wfp.timer;
|
||||||
|
|
||||||
|
import io.dapr.workflows.WorkflowActivity;
|
||||||
|
import io.dapr.workflows.WorkflowActivityContext;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class LogActivity implements WorkflowActivity {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TimerLogService logService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object run(WorkflowActivityContext ctx) {
|
||||||
|
Logger logger = LoggerFactory.getLogger(LogActivity.class);
|
||||||
|
Date now = new Date();
|
||||||
|
logger.info("Running Activity: {} at {}", ctx.getName(), now);
|
||||||
|
logService.logDate(now);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2025 The Dapr Authors
|
||||||
|
* 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.dapr.springboot.examples.wfp.timer;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class TimerLogService {
|
||||||
|
private final List<Date> logDates = new ArrayList<>();
|
||||||
|
|
||||||
|
public void logDate(Date date){
|
||||||
|
logDates.add(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearLog(){
|
||||||
|
logDates.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Date> getLogDates(){
|
||||||
|
return logDates;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2025 The Dapr Authors
|
||||||
|
* 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.dapr.springboot.examples.wfp.timer;
|
||||||
|
|
||||||
|
import io.dapr.workflows.Workflow;
|
||||||
|
import io.dapr.workflows.WorkflowStub;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class ZonedDateTimeTimerWorkflow implements Workflow {
|
||||||
|
@Override
|
||||||
|
public WorkflowStub create() {
|
||||||
|
return ctx -> {
|
||||||
|
ctx.getLogger().info("Starting Workflow: {}, instanceId: {}", ctx.getName(), ctx.getInstanceId());
|
||||||
|
|
||||||
|
ctx.getLogger().info("Let's call the first LogActivity at {}", new Date());
|
||||||
|
ctx.callActivity(LogActivity.class.getName()).await();
|
||||||
|
|
||||||
|
ZonedDateTime now = ZonedDateTime.now();
|
||||||
|
//Let's create a ZonedDateTime 10 seconds in the future
|
||||||
|
ZonedDateTime inTheFuture = now.plusSeconds(10);
|
||||||
|
ctx.getLogger().info("Creating a timer that due {} at: {}", inTheFuture, new Date());
|
||||||
|
ctx.createTimer(inTheFuture).await();
|
||||||
|
ctx.getLogger().info("The timer fired at: {}", new Date());
|
||||||
|
|
||||||
|
ctx.getLogger().info("Let's call the second LogActivity at {}", new Date());
|
||||||
|
ctx.callActivity(LogActivity.class.getName()).await();
|
||||||
|
|
||||||
|
ctx.complete(true);
|
||||||
|
ctx.getLogger().info("Workflow completed at {}", new Date());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -16,6 +16,7 @@ package io.dapr.springboot.examples.wfp;
|
||||||
import io.dapr.springboot.DaprAutoConfiguration;
|
import io.dapr.springboot.DaprAutoConfiguration;
|
||||||
import io.dapr.springboot.examples.wfp.continueasnew.CleanUpLog;
|
import io.dapr.springboot.examples.wfp.continueasnew.CleanUpLog;
|
||||||
import io.dapr.springboot.examples.wfp.remoteendpoint.Payload;
|
import io.dapr.springboot.examples.wfp.remoteendpoint.Payload;
|
||||||
|
import io.dapr.springboot.examples.wfp.timer.TimerLogService;
|
||||||
import io.dapr.workflows.client.WorkflowRuntimeStatus;
|
import io.dapr.workflows.client.WorkflowRuntimeStatus;
|
||||||
import io.github.microcks.testcontainers.MicrocksContainersEnsemble;
|
import io.github.microcks.testcontainers.MicrocksContainersEnsemble;
|
||||||
import io.restassured.RestAssured;
|
import io.restassured.RestAssured;
|
||||||
|
|
@ -25,10 +26,13 @@ import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import static io.restassured.RestAssured.given;
|
import static io.restassured.RestAssured.given;
|
||||||
|
import static org.awaitility.Awaitility.await;
|
||||||
import static org.hamcrest.CoreMatchers.containsString;
|
import static org.hamcrest.CoreMatchers.containsString;
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
@ -42,10 +46,14 @@ class WorkflowPatternsAppTests {
|
||||||
@Autowired
|
@Autowired
|
||||||
private MicrocksContainersEnsemble ensemble;
|
private MicrocksContainersEnsemble ensemble;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TimerLogService logService;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setUp() {
|
void setUp() {
|
||||||
RestAssured.baseURI = "http://localhost:" + 8080;
|
RestAssured.baseURI = "http://localhost:" + 8080;
|
||||||
org.testcontainers.Testcontainers.exposeHostPorts(8080);
|
org.testcontainers.Testcontainers.exposeHostPorts(8080);
|
||||||
|
logService.clearLog();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -201,4 +209,64 @@ class WorkflowPatternsAppTests {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testDurationTimer() throws InterruptedException {
|
||||||
|
|
||||||
|
String instanceId = given()
|
||||||
|
.when()
|
||||||
|
.post("/wfp/durationtimer")
|
||||||
|
.then()
|
||||||
|
.statusCode(200).extract().asString();
|
||||||
|
|
||||||
|
assertNotNull(instanceId);
|
||||||
|
|
||||||
|
// Check that the workflow completed successfully
|
||||||
|
await().atMost(Duration.ofSeconds(30))
|
||||||
|
.pollDelay(500, TimeUnit.MILLISECONDS)
|
||||||
|
.pollInterval(500, TimeUnit.MILLISECONDS)
|
||||||
|
.until(() -> {
|
||||||
|
System.out.println("Log Size: " + logService.getLogDates().size());
|
||||||
|
if( logService.getLogDates().size() == 2 ) {
|
||||||
|
long diffInMillis = Math.abs(logService.getLogDates().get(1).getTime() - logService.getLogDates().get(0).getTime());
|
||||||
|
long diff = TimeUnit.SECONDS.convert(diffInMillis, TimeUnit.MILLISECONDS);
|
||||||
|
System.out.println("First Log at: " + logService.getLogDates().get(0));
|
||||||
|
System.out.println("Second Log at: " + logService.getLogDates().get(1));
|
||||||
|
System.out.println("Diff in seconds: " + diff);
|
||||||
|
// The updated time differences should be between 9 and 11 seconds
|
||||||
|
return diff >= 9 && diff <= 11;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testZonedDateTimeTimer() throws InterruptedException {
|
||||||
|
|
||||||
|
String instanceId = given()
|
||||||
|
.when()
|
||||||
|
.post("/wfp/zoneddatetimetimer")
|
||||||
|
.then()
|
||||||
|
.statusCode(200).extract().asString();
|
||||||
|
|
||||||
|
assertNotNull(instanceId);
|
||||||
|
|
||||||
|
// Check that the workflow completed successfully
|
||||||
|
await().atMost(Duration.ofSeconds(30))
|
||||||
|
.pollDelay(500, TimeUnit.MILLISECONDS)
|
||||||
|
.pollInterval(500, TimeUnit.MILLISECONDS)
|
||||||
|
.until(() -> {
|
||||||
|
System.out.println("Log Size: " + logService.getLogDates().size());
|
||||||
|
if( logService.getLogDates().size() == 2 ) {
|
||||||
|
long diffInMillis = Math.abs(logService.getLogDates().get(1).getTime() - logService.getLogDates().get(0).getTime());
|
||||||
|
long diff = TimeUnit.SECONDS.convert(diffInMillis, TimeUnit.MILLISECONDS);
|
||||||
|
System.out.println("First Log at: " + logService.getLogDates().get(0));
|
||||||
|
System.out.println("Second Log at: " + logService.getLogDates().get(1));
|
||||||
|
System.out.println("Diff in seconds: " + diff);
|
||||||
|
// The updated time differences should be between 9 and 11 seconds
|
||||||
|
return diff >= 9 && diff <= 11;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue