mirror of https://github.com/dapr/java-sdk.git
Merge branch 'master' into dependabot/maven/dapr-spring/ch.qos.logback-logback-core-1.5.13
This commit is contained in:
commit
8df0f200a3
1
pom.xml
1
pom.xml
|
@ -62,6 +62,7 @@
|
|||
<commons-cli.version>1.9.0</commons-cli.version>
|
||||
<commons-io.version>2.14.0</commons-io.version>
|
||||
<zipkin.version>3.4.0</zipkin.version>
|
||||
<microcks.version>0.3.1</microcks.version>
|
||||
</properties>
|
||||
|
||||
<distributionManagement>
|
||||
|
|
|
@ -40,6 +40,12 @@
|
|||
<artifactId>rest-assured</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.microcks</groupId>
|
||||
<artifactId>microcks-testcontainers</artifactId>
|
||||
<version>${microcks.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -13,9 +13,12 @@ limitations under the License.
|
|||
|
||||
package io.dapr.springboot.examples.wfp;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.dapr.springboot.examples.wfp.continueasnew.CleanUpLog;
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
@Configuration
|
||||
public class WorkflowPatternsConfiguration {
|
||||
|
@ -23,4 +26,14 @@ public class WorkflowPatternsConfiguration {
|
|||
public CleanUpLog cleanUpLog(){
|
||||
return new CleanUpLog();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RestTemplate restTemplate() {
|
||||
return new RestTemplateBuilder().build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ObjectMapper mapper() {
|
||||
return new ObjectMapper();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,8 @@ import io.dapr.springboot.examples.wfp.externalevent.Decision;
|
|||
import io.dapr.springboot.examples.wfp.externalevent.ExternalEventWorkflow;
|
||||
import io.dapr.springboot.examples.wfp.fanoutin.FanOutInWorkflow;
|
||||
import io.dapr.springboot.examples.wfp.fanoutin.Result;
|
||||
import io.dapr.springboot.examples.wfp.remoteendpoint.Payload;
|
||||
import io.dapr.springboot.examples.wfp.remoteendpoint.RemoteEndpointWorkflow;
|
||||
import io.dapr.workflows.client.DaprWorkflowClient;
|
||||
import io.dapr.workflows.client.WorkflowInstanceStatus;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -53,6 +55,7 @@ public class WorkflowPatternsRestController {
|
|||
private Map<String, String> ordersToApprove = new HashMap<>();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Run Chain Demo Workflow
|
||||
* @return the output of the ChainWorkflow execution
|
||||
|
@ -137,4 +140,17 @@ public class WorkflowPatternsRestController {
|
|||
return workflowInstanceStatus.readOutputAs(CleanUpLog.class);
|
||||
}
|
||||
|
||||
@PostMapping("wfp/remote-endpoint")
|
||||
public Payload remoteEndpoint(@RequestBody Payload payload)
|
||||
throws TimeoutException {
|
||||
|
||||
String instanceId = daprWorkflowClient.scheduleNewWorkflow(RemoteEndpointWorkflow.class, payload);
|
||||
logger.info("Workflow instance " + instanceId + " started");
|
||||
|
||||
WorkflowInstanceStatus workflowInstanceStatus = daprWorkflowClient
|
||||
.waitForInstanceCompletion(instanceId, null, true);
|
||||
System.out.printf("workflow instance with ID: %s completed.", instanceId);
|
||||
return workflowInstanceStatus.readOutputAs(Payload.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright 2023 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.remoteendpoint;
|
||||
|
||||
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.beans.factory.annotation.Value;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
@Component
|
||||
public class CallRemoteEndpointActivity implements WorkflowActivity {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(CallRemoteEndpointActivity.class);
|
||||
|
||||
@Value("${application.process-base-url:}")
|
||||
private String processBaseURL;
|
||||
|
||||
@Autowired
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
|
||||
@Override
|
||||
public Object run(WorkflowActivityContext ctx) {
|
||||
logger.info("Starting Activity: " + ctx.getName());
|
||||
var payload = ctx.getInput(Payload.class);
|
||||
|
||||
HttpEntity<Payload> request =
|
||||
new HttpEntity<>(payload);
|
||||
payload = restTemplate.postForObject(processBaseURL + "/process", request, Payload.class);
|
||||
|
||||
logger.info("Payload from the remote service: " + payload);
|
||||
|
||||
return payload;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* 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.remoteendpoint;
|
||||
|
||||
public class Payload {
|
||||
private String id;
|
||||
private String content;
|
||||
private Boolean processed = false;
|
||||
|
||||
public Payload(String id, String content) {
|
||||
this.id = id;
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public Payload() {
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public Boolean getProcessed() {
|
||||
return processed;
|
||||
}
|
||||
|
||||
public void setProcessed(Boolean processed) {
|
||||
this.processed = processed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Payload{" +
|
||||
"id='" + id + '\'' +
|
||||
", content='" + content + '\'' +
|
||||
", processed=" + processed +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright 2023 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.remoteendpoint;
|
||||
|
||||
import io.dapr.workflows.Workflow;
|
||||
import io.dapr.workflows.WorkflowStub;
|
||||
import io.dapr.workflows.WorkflowTaskOptions;
|
||||
import io.dapr.workflows.WorkflowTaskRetryPolicy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
@Component
|
||||
public class RemoteEndpointWorkflow implements Workflow {
|
||||
|
||||
@Override
|
||||
public WorkflowStub create() {
|
||||
return ctx -> {
|
||||
ctx.getLogger().info("Starting Workflow: " + ctx.getName());
|
||||
|
||||
Payload payload = ctx.getInput(Payload.class);
|
||||
payload = ctx.callActivity(CallRemoteEndpointActivity.class.getName(), payload ,
|
||||
new WorkflowTaskOptions(new WorkflowTaskRetryPolicy(5,
|
||||
Duration.ofSeconds(2), 1.0, Duration.ofSeconds(10), Duration.ofSeconds(20))),
|
||||
Payload.class).await();
|
||||
|
||||
ctx.getLogger().info("Workflow finished with result: " + payload);
|
||||
ctx.complete(payload);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -15,11 +15,19 @@ package io.dapr.springboot.examples.wfp;
|
|||
|
||||
import io.dapr.testcontainers.Component;
|
||||
import io.dapr.testcontainers.DaprContainer;
|
||||
import io.github.microcks.testcontainers.MicrocksContainersEnsemble;
|
||||
import org.junit.runner.Description;
|
||||
import org.junit.runners.model.Statement;
|
||||
import org.springframework.boot.test.context.TestConfiguration;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.test.context.DynamicPropertyRegistrar;
|
||||
import org.testcontainers.DockerClientFactory;
|
||||
import org.testcontainers.containers.Network;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static io.dapr.testcontainers.DaprContainerConstants.DAPR_RUNTIME_IMAGE_TAG;
|
||||
|
||||
|
@ -28,16 +36,66 @@ public class DaprTestContainersConfig {
|
|||
|
||||
@Bean
|
||||
@ServiceConnection
|
||||
public DaprContainer daprContainer() {
|
||||
public DaprContainer daprContainer(Network network) {
|
||||
|
||||
return new DaprContainer(DAPR_RUNTIME_IMAGE_TAG)
|
||||
.withAppName("workflow-patterns-app")
|
||||
.withComponent(new Component("kvstore", "state.in-memory", "v1", Collections.singletonMap("actorStateStore", String.valueOf(true))))
|
||||
.withAppPort(8080)
|
||||
.withNetwork(network)
|
||||
.withAppHealthCheckPath("/actuator/health")
|
||||
.withAppChannelAddress("host.testcontainers.internal");
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
MicrocksContainersEnsemble microcksEnsemble(Network network) {
|
||||
return new MicrocksContainersEnsemble(network, "quay.io/microcks/microcks-uber:1.11.2")
|
||||
.withAccessToHost(true) // We need this to access our webapp while it runs
|
||||
.withMainArtifacts("third-parties/remote-http-service.yaml");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DynamicPropertyRegistrar endpointsProperties(MicrocksContainersEnsemble ensemble) {
|
||||
// We need to replace the default endpoints with those provided by Microcks.
|
||||
return (properties) -> {
|
||||
properties.add("application.process-base-url", () -> ensemble.getMicrocksContainer()
|
||||
.getRestMockEndpoint("API Payload Processor", "1.0.0"));
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Network getDaprNetwork(Environment env) {
|
||||
boolean reuse = env.getProperty("reuse", Boolean.class, false);
|
||||
if (reuse) {
|
||||
Network defaultDaprNetwork = new Network() {
|
||||
@Override
|
||||
public String getId() {
|
||||
return "dapr-network";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Statement apply(Statement base, Description description) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
List<com.github.dockerjava.api.model.Network> networks = DockerClientFactory.instance().client().listNetworksCmd()
|
||||
.withNameFilter("dapr-network").exec();
|
||||
if (networks.isEmpty()) {
|
||||
Network.builder().createNetworkCmdModifier(cmd -> cmd.withName("dapr-network")).build().getId();
|
||||
return defaultDaprNetwork;
|
||||
} else {
|
||||
return defaultDaprNetwork;
|
||||
}
|
||||
} else {
|
||||
return Network.newNetwork();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@ package io.dapr.springboot.examples.wfp;
|
|||
import io.dapr.client.DaprClient;
|
||||
import io.dapr.springboot.DaprAutoConfiguration;
|
||||
import io.dapr.springboot.examples.wfp.continueasnew.CleanUpLog;
|
||||
import io.dapr.springboot.examples.wfp.remoteendpoint.Payload;
|
||||
import io.github.microcks.testcontainers.MicrocksContainersEnsemble;
|
||||
import io.restassured.RestAssured;
|
||||
import io.restassured.http.ContentType;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
@ -39,6 +41,9 @@ class WorkflowPatternsAppTests {
|
|||
@Autowired
|
||||
private DaprClient daprClient;
|
||||
|
||||
@Autowired
|
||||
private MicrocksContainersEnsemble ensemble;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
RestAssured.baseURI = "http://localhost:" + 8080;
|
||||
|
@ -139,4 +144,20 @@ class WorkflowPatternsAppTests {
|
|||
assertEquals(5, cleanUpLog.getCleanUpTimes());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRemoteEndpoint() {
|
||||
|
||||
Payload payload = given().contentType(ContentType.JSON)
|
||||
.body(new Payload("123", "content goes here"))
|
||||
.when()
|
||||
.post("/wfp/remote-endpoint")
|
||||
.then()
|
||||
.statusCode(200).extract().as(Payload.class);
|
||||
|
||||
assertEquals(true, payload.getProcessed());
|
||||
|
||||
assertEquals(2, ensemble.getMicrocksContainer()
|
||||
.getServiceInvocationsCount("API Payload Processor", "1.0.0"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
---
|
||||
openapi: 3.0.2
|
||||
info:
|
||||
title: API Payload Processor
|
||||
version: 1.0.0
|
||||
description: API definition of API Payload Processor sample app
|
||||
contact:
|
||||
name: Salaboy
|
||||
url: http://github.com/salaboy
|
||||
email: salaboy@gmail.com
|
||||
license:
|
||||
name: MIT License
|
||||
url: https://opensource.org/licenses/MIT
|
||||
paths:
|
||||
/process:
|
||||
summary: Process payload
|
||||
post:
|
||||
tags:
|
||||
- process
|
||||
x-microcks-operation:
|
||||
dispatcher: SCRIPT
|
||||
dispatcherRules: |
|
||||
def retries = store.get("retries") ?:"first"
|
||||
if (retries == "first") {
|
||||
store.put("retries", "second", 60)
|
||||
return "Error"
|
||||
}
|
||||
store.delete("retries")
|
||||
return "Payload"
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Payload'
|
||||
required: true
|
||||
responses:
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Payload'
|
||||
examples:
|
||||
Payload:
|
||||
value:
|
||||
id: 123
|
||||
content: payload content here
|
||||
processed: true
|
||||
description: Process payload
|
||||
"500":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
message:
|
||||
type: string
|
||||
description: Error message
|
||||
examples:
|
||||
Error:
|
||||
value:
|
||||
message: Something unexpected happened
|
||||
description: Error payload
|
||||
operationId: Process
|
||||
summary: Process incoming payload
|
||||
components:
|
||||
schemas:
|
||||
Payload:
|
||||
title: Payload to be processed
|
||||
description: Payload to be processed following the Payload type's schema.
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
description: Payload Id
|
||||
type: string
|
||||
content:
|
||||
description: Payload Content
|
||||
type: string
|
||||
processed:
|
||||
description: Is the Payload processed
|
||||
type: boolean
|
||||
required:
|
||||
- id
|
||||
- content
|
||||
additionalProperties: false
|
||||
tags:
|
||||
- name: payload
|
||||
description: Payload resource
|
Loading…
Reference in New Issue