Merge branch 'v1.12' into submodules_1.12

This commit is contained in:
Mark Fussell 2023-10-05 17:08:33 -07:00 committed by GitHub
commit 4b972f68e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 150 additions and 29 deletions

View File

@ -94,6 +94,21 @@ The diagram below shows an example of how this works. If you have 1 instance of
Dapr can run on a variety of [hosting platforms]({{< ref hosting >}}). To enable service discovery and service invocation, Dapr uses pluggable [name resolution components]({{< ref supported-name-resolution >}}). For example, the Kubernetes name resolution component uses the Kubernetes DNS service to resolve the location of other applications running in the cluster. Self-hosted machines can use the mDNS name resolution component. The Consul name resolution component can be used in any hosting environment, including Kubernetes or self-hosted.
### Streaming for HTTP service invocation
You can handle data as a stream in HTTP service invocation. This can offer improvements in performance and memory utilization when using Dapr to invoke another service using HTTP with large request or response bodies.
The diagram below demonstrates the six steps of data flow.
<img src="/images/service-invocation-simple.webp" width=600 alt="Diagram showing the steps of service invocation described in the table below" />
1. Request: "App A" to "Dapr sidecar A"
1. Request: "Dapr sidecar A" to "Dapr sidecar B"
1. Request: "Dapr sidecar B" to "App B"
1. Response: "App B" to "Dapr sidecar B"
1. Response: "Dapr sidecar B" to "Dapr sidecar A"
1. Response: "Dapr sidecar A" to "App A"
## Example Architecture
Following the above call sequence, suppose you have the applications as described in the [Hello World tutorial](https://github.com/dapr/quickstarts/blob/master/tutorials/hello-world/README.md), where a python app invokes a node.js app. In such a scenario, the python app would be "Service A" , and a Node.js app would be "Service B".

View File

@ -162,7 +162,7 @@ APIs that generate random numbers, random UUIDs, or the current date are _non-de
For example, instead of this:
{{< tabs ".NET" >}}
{{< tabs ".NET" Java >}}
{{% codetab %}}
@ -175,11 +175,22 @@ string randomString = GetRandomString();
{{% /codetab %}}
{{% codetab %}}
```java
// DON'T DO THIS!
Instant currentTime = Instant.now();
UUID newIdentifier = UUID.randomUUID();
string randomString = GetRandomString();
```
{{% /codetab %}}
{{< /tabs >}}
Do this:
{{< tabs ".NET" >}}
{{< tabs ".NET" Java >}}
{{% codetab %}}
@ -192,6 +203,17 @@ string randomString = await context.CallActivityAsync<string>("GetRandomString")
{{% /codetab %}}
{{% codetab %}}
```java
// Do this!!
Instant currentTime = context.getCurrentInstant();
Guid newIdentifier = context.NewGuid();
String randomString = context.callActivity(GetRandomString.class.getName(), String.class).await();
```
{{% /codetab %}}
{{< /tabs >}}
@ -202,20 +224,58 @@ Instead, workflows should interact with external state _indirectly_ using workfl
For example, instead of this:
{{< tabs ".NET" Java >}}
{{% codetab %}}
```csharp
// DON'T DO THIS!
string configuration = Environment.GetEnvironmentVariable("MY_CONFIGURATION")!;
string data = await new HttpClient().GetStringAsync("https://example.com/api/data");
```
{{% /codetab %}}
{{% codetab %}}
```java
// DON'T DO THIS!
String configuration = System.getenv("MY_CONFIGURATION");
HttpRequest request = HttpRequest.newBuilder().uri(new URI("https://postman-echo.com/post")).GET().build();
HttpResponse<String> response = HttpClient.newBuilder().build().send(request, HttpResponse.BodyHandlers.ofString());
```
{{% /codetab %}}
{{< /tabs >}}
Do this:
{{< tabs ".NET" Java >}}
{{% codetab %}}
```csharp
// Do this!!
string configuation = workflowInput.Configuration; // imaginary workflow input argument
string data = await context.CallActivityAsync<string>("MakeHttpCall", "https://example.com/api/data");
```
{{% /codetab %}}
{{% codetab %}}
```java
// Do this!!
String configuation = ctx.getInput(InputType.class).getConfiguration(); // imaginary workflow input argument
String data = ctx.callActivity(MakeHttpCall.class, "https://example.com/api/data", String.class).await();
```
{{% /codetab %}}
{{< /tabs >}}
#### Workflow functions must execute only on the workflow dispatch thread.
The implementation of each language SDK requires that all workflow function operations operate on the same thread (goroutine, etc.) that the function was scheduled on. Workflow functions must never:
- Schedule background threads, or
@ -225,20 +285,58 @@ Failure to follow this rule could result in undefined behavior. Any background p
For example, instead of this:
{{< tabs ".NET" Java >}}
{{% codetab %}}
```csharp
// DON'T DO THIS!
Task t = Task.Run(() => context.CallActivityAsync("DoSomething"));
await context.CreateTimer(5000).ConfigureAwait(false);
```
{{% /codetab %}}
{{% codetab %}}
```java
// DON'T DO THIS!
new Thread(() -> {
ctx.callActivity(DoSomethingActivity.class.getName()).await();
}).start();
ctx.createTimer(Duration.ofSeconds(5)).await();
```
{{% /codetab %}}
{{< /tabs >}}
Do this:
{{< tabs ".NET" Java >}}
{{% codetab %}}
```csharp
// Do this!!
Task t = context.CallActivityAsync("DoSomething");
await context.CreateTimer(5000).ConfigureAwait(true);
```
{{% /codetab %}}
{{% codetab %}}
```java
// Do this!!
ctx.callActivity(DoSomethingActivity.class.getName()).await();
ctx.createTimer(Duration.ofSeconds(5)).await();
```
{{% /codetab %}}
{{< /tabs >}}
### Updating workflow code
Make sure updates you make to the workflow code maintain its determinism. A couple examples of code updates that can break workflow determinism:

View File

@ -464,7 +464,41 @@ public override async Task<object> RunAsync(WorkflowContext context, MyEntitySta
<!--java-->
```java
todo
public class MonitorWorkflow extends Workflow {
@Override
public WorkflowStub create() {
return ctx -> {
Duration nextSleepInterval;
var status = ctx.callActivity(DemoWorkflowStatusActivity.class.getName(), DemoStatusActivityOutput.class).await();
var isHealthy = status.getIsHealthy();
if (isHealthy) {
// Check less frequently when in a healthy state
nextSleepInterval = Duration.ofMinutes(60);
} else {
ctx.callActivity(DemoWorkflowAlertActivity.class.getName()).await();
// Check more frequently when in an unhealthy state
nextSleepInterval = Duration.ofMinutes(5);
}
// Put the workflow to sleep until the determined time
// Note: ctx.createTimer() method is not supported in the Java SDK yet
try {
TimeUnit.SECONDS.sleep(nextSleepInterval.getSeconds());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
// Restart from the beginning with the updated state
ctx.continueAsNew();
}
}
}
```
{{% /codetab %}}

View File

@ -15,7 +15,6 @@ For CLI there is no explicit opt-in, just the version that this was first made a
| Feature | Description | Setting | Documentation | Version introduced |
| --- | --- | --- | --- | --- |
| **Streaming for HTTP service invocation** | Enables (partial) support for using streams in HTTP service invocation; see below for more details. | `ServiceInvocationStreaming` | [Details]({{< ref "support-preview-features.md#streaming-for-http-service-invocation" >}}) | v1.10 |
| **Pluggable components** | Allows creating self-hosted gRPC-based components written in any language that supports gRPC. The following component APIs are supported: State stores, Pub/sub, Bindings | N/A | [Pluggable components concept]({{<ref "components-concept#pluggable-components" >}})| v1.9 |
| **Multi-App Run for Kubernetes** | Configure multiple Dapr applications from a single configuration file and run from a single command on Kubernetes | `dapr run -k -f` | [Multi-App Run]({{< ref multi-app-dapr-run.md >}}) | v1.10 |
| **Workflows** | Author workflows as code to automate and orchestrate tasks within your application, like messaging, state management, and failure handling | N/A | [Workflows concept]({{< ref "components-concept#workflows" >}})| v1.10 |
@ -24,28 +23,3 @@ For CLI there is no explicit opt-in, just the version that this was first made a
| **Actor State TTL** | Allow actors to save records to state stores with Time To Live (TTL) set to automatically clean up old data. In its current implementation, actor state with TTL may not be reflected correctly by clients, read [Actor State Transactions]({{< ref actors_api.md >}}) for more information. | `ActorStateTTL` | [Actor State Transactions]({{< ref actors_api.md >}}) | v1.11 |
| **Transactional Outbox** | Allows state operations for inserts and updates to be published to a configured pub/sub topic using a single transaction across the state store and the pub/sub | N/A | [Transactional Outbox Feature]({{< ref howto-outbox.md >}}) | v1.12 |
### Streaming for HTTP service invocation
Running Dapr with the `ServiceInvocationStreaming` feature flag enables partial support for handling data as a stream in HTTP service invocation. This can offer improvements in performance and memory utilization when using Dapr to invoke another service using HTTP with large request or response bodies.
The table below summarizes the current state of support for streaming in HTTP service invocation in Dapr, including the impact of enabling `ServiceInvocationStreaming`, in the example where "app A" is invoking "app B" using Dapr. There are six steps in the data flow, with various levels of support for handling data as a stream:
<img src="/images/service-invocation-simple.webp" width=600 alt="Diagram showing the steps of service invocation described in the table below" />
| Step | Handles data as a stream | Dapr 1.11 | Dapr 1.11 with<br/>`ServiceInvocationStreaming` |
|:---:|---|:---:|:---:|
| 1 | Request: "App A" to "Dapr sidecar A | <span role="img" aria-label="No"></span> | <span role="img" aria-label="No"></span> |
| 2 | Request: "Dapr sidecar A" to "Dapr sidecar B | <span role="img" aria-label="No"></span> | <span role="img" aria-label="Yes"></span> |
| 3 | Request: "Dapr sidecar B" to "App B" | <span role="img" aria-label="Yes"></span> | <span role="img" aria-label="Yes"></span> |
| 4 | Response: "App B" to "Dapr sidecar B" | <span role="img" aria-label="Yes"></span> | <span role="img" aria-label="Yes"></span> |
| 5 | Response: "Dapr sidecar B" to "Dapr sidecar A | <span role="img" aria-label="No"></span> | <span role="img" aria-label="Yes"></span> |
| 6 | Response: "Dapr sidecar A" to "App A | <span role="img" aria-label="No"></span> | <span role="img" aria-label="No"></span> |
Important notes:
- `ServiceInvocationStreaming` needs to be applied on caller sidecars only.
In the example above, streams are used for HTTP service invocation if `ServiceInvocationStreaming` is applied to the configuration of "app A" and its Dapr sidecar, regardless of whether the feature flag is enabled for "app B" and its sidecar.
- When `ServiceInvocationStreaming` is enabled, you should make sure that all services your app invokes using Dapr ("app B") are updated to Dapr 1.10 or higher, even if `ServiceInvocationStreaming` is not enabled for those sidecars.
Invoking an app using Dapr 1.9 or older is still possible, but those calls may fail unless you have applied a Dapr Resiliency policy with retries enabled.
> Full support for streaming for HTTP service invocation will be completed in a future Dapr version.