mirror of https://github.com/dapr/docs.git
				
				
				
			scaffold out docs for workflow java sdk
Signed-off-by: Hannah Hunter <hannahhunter@microsoft.com>
This commit is contained in:
		
							parent
							
								
									4d444bd12a
								
							
						
					
					
						commit
						0211dfef6e
					
				|  | @ -30,7 +30,25 @@ The Dapr sidecar doesn’t load any workflow definitions. Rather, the sidecar si | ||||||
| 
 | 
 | ||||||
| [Workflow activities]({{< ref "workflow-features-concepts.md#workflow-activites" >}}) are the basic unit of work in a workflow and are the tasks that get orchestrated in the business process. | [Workflow activities]({{< ref "workflow-features-concepts.md#workflow-activites" >}}) are the basic unit of work in a workflow and are the tasks that get orchestrated in the business process. | ||||||
| 
 | 
 | ||||||
| {{< tabs ".NET" Python >}} | {{< tabs Python ".NET" Java >}} | ||||||
|  | 
 | ||||||
|  | {{% codetab %}} | ||||||
|  | 
 | ||||||
|  | <!--python--> | ||||||
|  | 
 | ||||||
|  | Define the workflow activities you'd like your workflow to perform. Activities are a function definition and can take inputs and outputs. The following example creates a counter (activity) called `hello_act` that notifies users of the current counter value. `hello_act` is a function derived from a class called `WorkflowActivityContext`. | ||||||
|  | 
 | ||||||
|  | ```python | ||||||
|  | def hello_act(ctx: WorkflowActivityContext, input): | ||||||
|  |     global counter | ||||||
|  |     counter += input | ||||||
|  |     print(f'New counter value is: {counter}!', flush=True) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | [See the `hello_act` workflow activity in context.](https://github.com/dapr/python-sdk/blob/master/examples/demo_workflow/app.py#LL40C1-L43C59) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | {{% /codetab %}} | ||||||
| 
 | 
 | ||||||
| {{% codetab %}} | {{% codetab %}} | ||||||
| 
 | 
 | ||||||
|  | @ -102,29 +120,67 @@ public class ProcessPaymentActivity : WorkflowActivity<PaymentRequest, object> | ||||||
| 
 | 
 | ||||||
| {{% codetab %}} | {{% codetab %}} | ||||||
| 
 | 
 | ||||||
| <!--python--> | <!--java--> | ||||||
| 
 | 
 | ||||||
| Define the workflow activities you'd like your workflow to perform. Activities are a function definition and can take inputs and outputs. The following example creates a counter (activity) called `hello_act` that notifies users of the current counter value. `hello_act` is a function derived from a class called `WorkflowActivityContext`. | Define the workflow activities you'd like your workflow to perform.  | ||||||
| 
 | 
 | ||||||
| ```python | The activities called in the example below are: | ||||||
| def hello_act(ctx: WorkflowActivityContext, input): | - `need`: Receive notification of a new order. | ||||||
|     global counter | 
 | ||||||
|     counter += input | ### [activity] | ||||||
|     print(f'New counter value is: {counter}!', flush=True) | 
 | ||||||
|  | ```java | ||||||
|  | todo | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| [See the `hello_act` workflow activity in context.](https://github.com/dapr/python-sdk/blob/master/examples/demo_workflow/app.py#LL40C1-L43C59) | [See the full `todo` workflow activity example.](todo) | ||||||
| 
 | 
 | ||||||
|  | ### [activity] | ||||||
|  | 
 | ||||||
|  | ```java | ||||||
|  | todo | ||||||
|  | ``` | ||||||
|  | [See the full `todo` workflow activity example.](todo) | ||||||
|  | 
 | ||||||
|  | ### [todo] | ||||||
|  | 
 | ||||||
|  | ```java | ||||||
|  | todo | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | [See the full `todo` workflow activity example.](todo) | ||||||
| 
 | 
 | ||||||
| {{% /codetab %}} | {{% /codetab %}} | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| {{< /tabs >}} | {{< /tabs >}} | ||||||
| 
 | 
 | ||||||
| ## Write the workflow | ## Write the workflow | ||||||
| 
 | 
 | ||||||
| Next, register and call the activites in a workflow.  | Next, register and call the activites in a workflow.  | ||||||
| 
 | 
 | ||||||
| {{< tabs ".NET" Python >}} | {{< tabs Python ".NET" Java >}} | ||||||
|  | 
 | ||||||
|  | {{% codetab %}} | ||||||
|  | 
 | ||||||
|  | <!--python--> | ||||||
|  | 
 | ||||||
|  | The `hello_world_wf` function is derived from a class called `DaprWorkflowContext` with input and output parameter types. It also includes a `yield` statement that does the heavy lifting of the workflow and calls the workflow activities.  | ||||||
|  |   | ||||||
|  | ```python | ||||||
|  | def hello_world_wf(ctx: DaprWorkflowContext, input): | ||||||
|  |     print(f'{input}') | ||||||
|  |     yield ctx.call_activity(hello_act, input=1) | ||||||
|  |     yield ctx.call_activity(hello_act, input=10) | ||||||
|  |     yield ctx.wait_for_external_event("event1") | ||||||
|  |     yield ctx.call_activity(hello_act, input=100) | ||||||
|  |     yield ctx.call_activity(hello_act, input=1000) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | [See the `hello_world_wf` workflow in context.](https://github.com/dapr/python-sdk/blob/master/examples/demo_workflow/app.py#LL32C1-L38C51) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | {{% /codetab %}} | ||||||
| 
 | 
 | ||||||
| {{% codetab %}} | {{% codetab %}} | ||||||
| 
 | 
 | ||||||
|  | @ -171,21 +227,15 @@ The `OrderProcessingWorkflow` class is derived from a base class called `Workflo | ||||||
| 
 | 
 | ||||||
| {{% codetab %}} | {{% codetab %}} | ||||||
| 
 | 
 | ||||||
| <!--python--> | <!--java--> | ||||||
| 
 | 
 | ||||||
| The `hello_world_wf` function is derived from a class called `DaprWorkflowContext` with input and output parameter types. It also includes a `yield` statement that does the heavy lifting of the workflow and calls the workflow activities.  | Intro | ||||||
|   |   | ||||||
| ```python | ```java | ||||||
| def hello_world_wf(ctx: DaprWorkflowContext, input): | todo | ||||||
|     print(f'{input}') |  | ||||||
|     yield ctx.call_activity(hello_act, input=1) |  | ||||||
|     yield ctx.call_activity(hello_act, input=10) |  | ||||||
|     yield ctx.wait_for_external_event("event1") |  | ||||||
|     yield ctx.call_activity(hello_act, input=100) |  | ||||||
|     yield ctx.call_activity(hello_act, input=1000) |  | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| [See the `hello_world_wf` workflow in context.](https://github.com/dapr/python-sdk/blob/master/examples/demo_workflow/app.py#LL32C1-L38C51) | [See the `todo` workflow in context.](todo) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| {{% /codetab %}} | {{% /codetab %}} | ||||||
|  | @ -196,78 +246,7 @@ def hello_world_wf(ctx: DaprWorkflowContext, input): | ||||||
| 
 | 
 | ||||||
| Finally, compose the application using the workflow. | Finally, compose the application using the workflow. | ||||||
| 
 | 
 | ||||||
| {{< tabs ".NET" Python >}} | {{< tabs Python ".NET" Java >}} | ||||||
| 
 |  | ||||||
| {{% codetab %}} |  | ||||||
| 
 |  | ||||||
| <!--csharp--> |  | ||||||
| 
 |  | ||||||
| [In the following `Program.cs` example](https://github.com/dapr/dotnet-sdk/blob/master/examples/Workflow/WorkflowConsoleApp/Program.cs), for a basic ASP.NET order processing application using the .NET SDK, your project code would include: |  | ||||||
| 
 |  | ||||||
| - A NuGet package called `Dapr.Workflow` to receive the .NET SDK capabilities |  | ||||||
| - A builder with an extension method called `AddDaprWorkflow` |  | ||||||
|   - This will allow you to register workflows and workflow activities (tasks that workflows can schedule) |  | ||||||
| - HTTP API calls |  | ||||||
|   - One for submitting a new order |  | ||||||
|   - One for checking the status of an existing order |  | ||||||
| 
 |  | ||||||
| ```csharp |  | ||||||
| using Dapr.Workflow; |  | ||||||
| //... |  | ||||||
| 
 |  | ||||||
| // Dapr Workflows are registered as part of the service configuration |  | ||||||
| builder.Services.AddDaprWorkflow(options => |  | ||||||
| { |  | ||||||
|     // Note that it's also possible to register a lambda function as the workflow |  | ||||||
|     // or activity implementation instead of a class. |  | ||||||
|     options.RegisterWorkflow<OrderProcessingWorkflow>(); |  | ||||||
| 
 |  | ||||||
|     // These are the activities that get invoked by the workflow(s). |  | ||||||
|     options.RegisterActivity<NotifyActivity>(); |  | ||||||
|     options.RegisterActivity<ReserveInventoryActivity>(); |  | ||||||
|     options.RegisterActivity<ProcessPaymentActivity>(); |  | ||||||
| }); |  | ||||||
| 
 |  | ||||||
| WebApplication app = builder.Build(); |  | ||||||
| 
 |  | ||||||
| // POST starts new order workflow instance |  | ||||||
| app.MapPost("/orders", async (WorkflowEngineClient client, [FromBody] OrderPayload orderInfo) => |  | ||||||
| { |  | ||||||
|     if (orderInfo?.Name == null) |  | ||||||
|     { |  | ||||||
|         return Results.BadRequest(new |  | ||||||
|         { |  | ||||||
|             message = "Order data was missing from the request", |  | ||||||
|             example = new OrderPayload("Paperclips", 99.95), |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| //... |  | ||||||
| }); |  | ||||||
| 
 |  | ||||||
| // GET fetches state for order workflow to report status |  | ||||||
| app.MapGet("/orders/{orderId}", async (string orderId, WorkflowEngineClient client) => |  | ||||||
| { |  | ||||||
|     WorkflowState state = await client.GetWorkflowStateAsync(orderId, true); |  | ||||||
|     if (!state.Exists) |  | ||||||
|     { |  | ||||||
|         return Results.NotFound($"No order with ID = '{orderId}' was found."); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     var httpResponsePayload = new |  | ||||||
|     { |  | ||||||
|         details = state.ReadInputAs<OrderPayload>(), |  | ||||||
|         status = state.RuntimeStatus.ToString(), |  | ||||||
|         result = state.ReadOutputAs<OrderResult>(), |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
| //... |  | ||||||
| }).WithName("GetOrderInfoEndpoint"); |  | ||||||
| 
 |  | ||||||
| app.Run(); |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| {{% /codetab %}} |  | ||||||
| 
 | 
 | ||||||
| {{% codetab %}} | {{% codetab %}} | ||||||
| 
 | 
 | ||||||
|  | @ -356,6 +335,91 @@ if __name__ == '__main__': | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | {{% /codetab %}} | ||||||
|  | 
 | ||||||
|  | {{% codetab %}} | ||||||
|  | 
 | ||||||
|  | <!--csharp--> | ||||||
|  | 
 | ||||||
|  | [In the following `Program.cs` example](https://github.com/dapr/dotnet-sdk/blob/master/examples/Workflow/WorkflowConsoleApp/Program.cs), for a basic ASP.NET order processing application using the .NET SDK, your project code would include: | ||||||
|  | 
 | ||||||
|  | - A NuGet package called `Dapr.Workflow` to receive the .NET SDK capabilities | ||||||
|  | - A builder with an extension method called `AddDaprWorkflow` | ||||||
|  |   - This will allow you to register workflows and workflow activities (tasks that workflows can schedule) | ||||||
|  | - HTTP API calls | ||||||
|  |   - One for submitting a new order | ||||||
|  |   - One for checking the status of an existing order | ||||||
|  | 
 | ||||||
|  | ```csharp | ||||||
|  | using Dapr.Workflow; | ||||||
|  | //... | ||||||
|  | 
 | ||||||
|  | // Dapr Workflows are registered as part of the service configuration | ||||||
|  | builder.Services.AddDaprWorkflow(options => | ||||||
|  | { | ||||||
|  |     // Note that it's also possible to register a lambda function as the workflow | ||||||
|  |     // or activity implementation instead of a class. | ||||||
|  |     options.RegisterWorkflow<OrderProcessingWorkflow>(); | ||||||
|  | 
 | ||||||
|  |     // These are the activities that get invoked by the workflow(s). | ||||||
|  |     options.RegisterActivity<NotifyActivity>(); | ||||||
|  |     options.RegisterActivity<ReserveInventoryActivity>(); | ||||||
|  |     options.RegisterActivity<ProcessPaymentActivity>(); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | WebApplication app = builder.Build(); | ||||||
|  | 
 | ||||||
|  | // POST starts new order workflow instance | ||||||
|  | app.MapPost("/orders", async (WorkflowEngineClient client, [FromBody] OrderPayload orderInfo) => | ||||||
|  | { | ||||||
|  |     if (orderInfo?.Name == null) | ||||||
|  |     { | ||||||
|  |         return Results.BadRequest(new | ||||||
|  |         { | ||||||
|  |             message = "Order data was missing from the request", | ||||||
|  |             example = new OrderPayload("Paperclips", 99.95), | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | //... | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | // GET fetches state for order workflow to report status | ||||||
|  | app.MapGet("/orders/{orderId}", async (string orderId, WorkflowEngineClient client) => | ||||||
|  | { | ||||||
|  |     WorkflowState state = await client.GetWorkflowStateAsync(orderId, true); | ||||||
|  |     if (!state.Exists) | ||||||
|  |     { | ||||||
|  |         return Results.NotFound($"No order with ID = '{orderId}' was found."); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     var httpResponsePayload = new | ||||||
|  |     { | ||||||
|  |         details = state.ReadInputAs<OrderPayload>(), | ||||||
|  |         status = state.RuntimeStatus.ToString(), | ||||||
|  |         result = state.ReadOutputAs<OrderResult>(), | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  | //... | ||||||
|  | }).WithName("GetOrderInfoEndpoint"); | ||||||
|  | 
 | ||||||
|  | app.Run(); | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | {{% /codetab %}} | ||||||
|  | 
 | ||||||
|  | {{% codetab %}} | ||||||
|  | 
 | ||||||
|  | <!--java--> | ||||||
|  | 
 | ||||||
|  | [In the following example](todo), for a basic Java hello world application using the Java SDK, your project code would include: | ||||||
|  | 
 | ||||||
|  | - A Java package called `todo` to receive the Java SDK capabilities. | ||||||
|  |   | ||||||
|  | ```java | ||||||
|  | todo | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
| {{% /codetab %}} | {{% /codetab %}} | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -377,5 +441,6 @@ Now that you've authored a workflow, learn how to manage it. | ||||||
| - [Workflow overview]({{< ref workflow-overview.md >}}) | - [Workflow overview]({{< ref workflow-overview.md >}}) | ||||||
| - [Workflow API reference]({{< ref workflow_api.md >}}) | - [Workflow API reference]({{< ref workflow_api.md >}}) | ||||||
| - Try out the full SDK examples: | - Try out the full SDK examples: | ||||||
|   - [.NET example](https://github.com/dapr/dotnet-sdk/tree/master/examples/Workflow) |  | ||||||
|   - [Python example](https://github.com/dapr/python-sdk/tree/master/examples/demo_workflow) |   - [Python example](https://github.com/dapr/python-sdk/tree/master/examples/demo_workflow) | ||||||
|  |   - [.NET example](https://github.com/dapr/dotnet-sdk/tree/master/examples/Workflow) | ||||||
|  |   - [Java example](todo) | ||||||
|  |  | ||||||
|  | @ -8,43 +8,7 @@ description: Manage and run workflows | ||||||
| 
 | 
 | ||||||
| Now that you've [authored the workflow and its activities in your application]({{< ref howto-author-workflow.md >}}), you can start, terminate, and get information about the workflow using HTTP API calls. For more information, read the [workflow API reference]({{< ref workflow_api.md >}}). | Now that you've [authored the workflow and its activities in your application]({{< ref howto-author-workflow.md >}}), you can start, terminate, and get information about the workflow using HTTP API calls. For more information, read the [workflow API reference]({{< ref workflow_api.md >}}). | ||||||
| 
 | 
 | ||||||
| {{< tabs ".NET" Python HTTP >}} | {{< tabs Python ".NET" Java HTTP >}} | ||||||
| 
 |  | ||||||
| <!--NET--> |  | ||||||
| {{% codetab %}} |  | ||||||
| 
 |  | ||||||
| Manage your workflow within your code. In the `OrderProcessingWorkflow` example from the [Author a workflow]({{< ref "howto-author-workflow.md#write-the-application" >}}) guide, the workflow is registered in the code. You can now start, terminate, and get information about a running workflow: |  | ||||||
| 
 |  | ||||||
| ```csharp |  | ||||||
| string orderId = "exampleOrderId"; |  | ||||||
| string workflowComponent = "dapr"; |  | ||||||
| string workflowName = "OrderProcessingWorkflow"; |  | ||||||
| OrderPayload input = new OrderPayload("Paperclips", 99.95); |  | ||||||
| Dictionary<string, string> workflowOptions; // This is an optional parameter |  | ||||||
| 
 |  | ||||||
| // Start the workflow. This returns back a "StartWorkflowResponse" which contains the instance ID for the particular workflow instance. |  | ||||||
| StartWorkflowResponse startResponse = await daprClient.StartWorkflowAsync(orderId, workflowComponent, workflowName, input, workflowOptions); |  | ||||||
| 
 |  | ||||||
| // Get information on the workflow. This response contains information such as the status of the workflow, when it started, and more! |  | ||||||
| GetWorkflowResponse getResponse = await daprClient.GetWorkflowAsync(orderId, workflowComponent, workflowName); |  | ||||||
| 
 |  | ||||||
| // Terminate the workflow |  | ||||||
| await daprClient.TerminateWorkflowAsync(orderId, workflowComponent); |  | ||||||
| 
 |  | ||||||
| // Raise an event (an incoming purchase order) that your workflow will wait for. This returns the item waiting to be purchased. |  | ||||||
| await daprClient.RaiseWorkflowEventAsync(orderId, workflowComponent, workflowName, input); |  | ||||||
| 
 |  | ||||||
| // Pause |  | ||||||
| await daprClient.PauseWorkflowAsync(orderId, workflowComponent); |  | ||||||
| 
 |  | ||||||
| // Resume |  | ||||||
| await daprClient.ResumeWorkflowAsync(orderId, workflowComponent); |  | ||||||
| 
 |  | ||||||
| // Purge |  | ||||||
| await daprClient.PurgeWorkflowAsync(orderId, workflowComponent); |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| {{% /codetab %}} |  | ||||||
| 
 | 
 | ||||||
| <!--Python--> | <!--Python--> | ||||||
| {{% codetab %}} | {{% codetab %}} | ||||||
|  | @ -95,6 +59,53 @@ d.terminate_workflow(instance_id=instanceId, workflow_component=workflowComponen | ||||||
| 
 | 
 | ||||||
| {{% /codetab %}} | {{% /codetab %}} | ||||||
| 
 | 
 | ||||||
|  | <!--NET--> | ||||||
|  | {{% codetab %}} | ||||||
|  | 
 | ||||||
|  | Manage your workflow within your code. In the `OrderProcessingWorkflow` example from the [Author a workflow]({{< ref "howto-author-workflow.md#write-the-application" >}}) guide, the workflow is registered in the code. You can now start, terminate, and get information about a running workflow: | ||||||
|  | 
 | ||||||
|  | ```csharp | ||||||
|  | string orderId = "exampleOrderId"; | ||||||
|  | string workflowComponent = "dapr"; | ||||||
|  | string workflowName = "OrderProcessingWorkflow"; | ||||||
|  | OrderPayload input = new OrderPayload("Paperclips", 99.95); | ||||||
|  | Dictionary<string, string> workflowOptions; // This is an optional parameter | ||||||
|  | 
 | ||||||
|  | // Start the workflow. This returns back a "StartWorkflowResponse" which contains the instance ID for the particular workflow instance. | ||||||
|  | StartWorkflowResponse startResponse = await daprClient.StartWorkflowAsync(orderId, workflowComponent, workflowName, input, workflowOptions); | ||||||
|  | 
 | ||||||
|  | // Get information on the workflow. This response contains information such as the status of the workflow, when it started, and more! | ||||||
|  | GetWorkflowResponse getResponse = await daprClient.GetWorkflowAsync(orderId, workflowComponent, workflowName); | ||||||
|  | 
 | ||||||
|  | // Terminate the workflow | ||||||
|  | await daprClient.TerminateWorkflowAsync(orderId, workflowComponent); | ||||||
|  | 
 | ||||||
|  | // Raise an event (an incoming purchase order) that your workflow will wait for. This returns the item waiting to be purchased. | ||||||
|  | await daprClient.RaiseWorkflowEventAsync(orderId, workflowComponent, workflowName, input); | ||||||
|  | 
 | ||||||
|  | // Pause | ||||||
|  | await daprClient.PauseWorkflowAsync(orderId, workflowComponent); | ||||||
|  | 
 | ||||||
|  | // Resume | ||||||
|  | await daprClient.ResumeWorkflowAsync(orderId, workflowComponent); | ||||||
|  | 
 | ||||||
|  | // Purge | ||||||
|  | await daprClient.PurgeWorkflowAsync(orderId, workflowComponent); | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | {{% /codetab %}} | ||||||
|  | 
 | ||||||
|  | <!--Python--> | ||||||
|  | {{% codetab %}} | ||||||
|  | 
 | ||||||
|  | Manage your workflow within your code. In the workflow example from the [Author a workflow]({{< ref "howto-author-workflow.md#write-the-application" >}}) guide, the workflow is registered in the code using the following APIs: | ||||||
|  | 
 | ||||||
|  | ```java | ||||||
|  | todo | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | {{% /codetab %}} | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| <!--HTTP--> | <!--HTTP--> | ||||||
| {{% codetab %}} | {{% codetab %}} | ||||||
|  | @ -172,6 +183,8 @@ Learn more about these HTTP calls in the [workflow API reference guide]({{< ref | ||||||
| ## Next steps | ## Next steps | ||||||
| - [Try out the Workflow quickstart]({{< ref workflow-quickstart.md >}}) | - [Try out the Workflow quickstart]({{< ref workflow-quickstart.md >}}) | ||||||
| - Try out the full SDK examples: | - Try out the full SDK examples: | ||||||
|   - [.NET example](https://github.com/dapr/dotnet-sdk/tree/master/examples/Workflow) |  | ||||||
|   - [Python example](https://github.com/dapr/python-sdk/blob/master/examples/demo_workflow/app.py) |   - [Python example](https://github.com/dapr/python-sdk/blob/master/examples/demo_workflow/app.py) | ||||||
|  |   - [.NET example](https://github.com/dapr/dotnet-sdk/tree/master/examples/Workflow) | ||||||
|  |   - [Java example](todo) | ||||||
|  | 
 | ||||||
| - [Workflow API reference]({{< ref workflow_api.md >}}) | - [Workflow API reference]({{< ref workflow_api.md >}}) | ||||||
|  |  | ||||||
|  | @ -83,9 +83,9 @@ You can use the following SDKs to author a workflow. | ||||||
| 
 | 
 | ||||||
| | Language stack | Package | | | Language stack | Package | | ||||||
| | - | - | | | - | - | | ||||||
| | .NET | [Dapr.Workflow](https://www.nuget.org/profiles/dapr.io) | |  | ||||||
| | Python | [dapr-ext-workflow](https://github.com/dapr/python-sdk/tree/master/ext/dapr-ext-workflow) | | | Python | [dapr-ext-workflow](https://github.com/dapr/python-sdk/tree/master/ext/dapr-ext-workflow) | | ||||||
| 
 | | .NET | [Dapr.Workflow](https://www.nuget.org/profiles/dapr.io) | | ||||||
|  | | Java | need | | ||||||
| 
 | 
 | ||||||
| ## Try out workflows | ## Try out workflows | ||||||
| 
 | 
 | ||||||
|  | @ -96,8 +96,9 @@ Want to put workflows to the test? Walk through the following quickstart and tut | ||||||
| | Quickstart/tutorial | Description | | | Quickstart/tutorial | Description | | ||||||
| | ------------------- | ----------- | | | ------------------- | ----------- | | ||||||
| | [Workflow quickstart]({{< ref workflow-quickstart.md >}}) | Run a .NET workflow application with four workflow activities to see Dapr Workflow in action  | | | [Workflow quickstart]({{< ref workflow-quickstart.md >}}) | Run a .NET workflow application with four workflow activities to see Dapr Workflow in action  | | ||||||
| | [Workflow .NET SDK example](https://github.com/dapr/dotnet-sdk/tree/master/examples/Workflow) | Learn how to create a Dapr Workflow and invoke it using ASP.NET Core web APIs. | |  | ||||||
| | [Workflow Python SDK example](https://github.com/dapr/python-sdk/tree/master/examples/demo_workflow) | Learn how to create a Dapr Workflow and invoke it using the Python `DaprClient` package. | | | [Workflow Python SDK example](https://github.com/dapr/python-sdk/tree/master/examples/demo_workflow) | Learn how to create a Dapr Workflow and invoke it using the Python `DaprClient` package. | | ||||||
|  | | [Workflow .NET SDK example](https://github.com/dapr/dotnet-sdk/tree/master/examples/Workflow) | Learn how to create a Dapr Workflow and invoke it using ASP.NET Core web APIs. | | ||||||
|  | | [Workflow Java SDK example](todo) | Learn how to create a Dapr Workflow and invoke it using the Java `need` package. | | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| ### Start using workflows directly in your app | ### Start using workflows directly in your app | ||||||
|  |  | ||||||
|  | @ -21,242 +21,9 @@ In this guide, you'll: | ||||||
| <img src="/images/workflow-quickstart-overview.png" width=800 style="padding-bottom:15px;"> | <img src="/images/workflow-quickstart-overview.png" width=800 style="padding-bottom:15px;"> | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| {{< tabs ".NET" "Python" >}} | {{< tabs "Python" ".NET" "Java" >}} | ||||||
| 
 | 
 | ||||||
|  <!-- .NET --> | <!-- Python --> | ||||||
| {{% codetab %}} |  | ||||||
| 
 |  | ||||||
| The `order-processor` console app starts and manages the lifecycle of an order processing workflow that stores and retrieves data in a state store. The workflow consists of four workflow activities, or tasks: |  | ||||||
| - `NotifyActivity`: Utilizes a logger to print out messages throughout the workflow |  | ||||||
| - `ReserveInventoryActivity`: Checks the state store to ensure that there is enough inventory for the purchase |  | ||||||
| - `ProcessPaymentActivity`: Processes and authorizes the payment |  | ||||||
| - `UpdateInventoryActivity`: Removes the requested items from the state store and updates the store with the new remaining inventory value |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| ### Step 1: Pre-requisites |  | ||||||
| 
 |  | ||||||
| For this example, you will need: |  | ||||||
| 
 |  | ||||||
| - [Dapr CLI and initialized environment](https://docs.dapr.io/getting-started). |  | ||||||
| - [.NET SDK or .NET 6 SDK installed](https://dotnet.microsoft.com/download). |  | ||||||
| <!-- IGNORE_LINKS --> |  | ||||||
| - [Docker Desktop](https://www.docker.com/products/docker-desktop) |  | ||||||
| <!-- END_IGNORE --> |  | ||||||
| 
 |  | ||||||
| ### Step 2: Set up the environment |  | ||||||
| 
 |  | ||||||
| Clone the [sample provided in the Quickstarts repo](https://github.com/dapr/quickstarts/tree/master/workflows). |  | ||||||
| 
 |  | ||||||
| ```bash |  | ||||||
| git clone https://github.com/dapr/quickstarts.git |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| In a new terminal window, navigate to the `order-processor` directory: |  | ||||||
| 
 |  | ||||||
| ```bash |  | ||||||
| cd workflows/csharp/sdk/order-processor |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ### Step 3: Run the order processor app |  | ||||||
| 
 |  | ||||||
| In the terminal, start the order processor app alongside a Dapr sidecar: |  | ||||||
| 
 |  | ||||||
| ```bash |  | ||||||
| dapr run --app-id order-processor dotnet run |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| This starts the `order-processor` app with unique workflow ID and runs the workflow activities.  |  | ||||||
| 
 |  | ||||||
| Expected output: |  | ||||||
| 
 |  | ||||||
| ``` |  | ||||||
| == APP == Starting workflow 6d2abcc9 purchasing 10 Cars |  | ||||||
| 
 |  | ||||||
| == APP == info: Microsoft.DurableTask.Client.Grpc.GrpcDurableTaskClient[40] |  | ||||||
| == APP ==       Scheduling new OrderProcessingWorkflow orchestration with instance ID '6d2abcc9' and 47 bytes of input data. |  | ||||||
| == APP == info: WorkflowConsoleApp.Activities.NotifyActivity[0] |  | ||||||
| == APP ==       Received order 6d2abcc9 for 10 Cars at $15000 |  | ||||||
| == APP == info: WorkflowConsoleApp.Activities.ReserveInventoryActivity[0] |  | ||||||
| == APP ==       Reserving inventory for order 6d2abcc9 of 10 Cars |  | ||||||
| == APP == info: WorkflowConsoleApp.Activities.ReserveInventoryActivity[0] |  | ||||||
| == APP ==       There are: 100, Cars available for purchase |  | ||||||
| 
 |  | ||||||
| == APP == Your workflow has started. Here is the status of the workflow: Dapr.Workflow.WorkflowState |  | ||||||
| 
 |  | ||||||
| == APP == info: WorkflowConsoleApp.Activities.ProcessPaymentActivity[0] |  | ||||||
| == APP ==       Processing payment: 6d2abcc9 for 10 Cars at $15000 |  | ||||||
| == APP == info: WorkflowConsoleApp.Activities.ProcessPaymentActivity[0] |  | ||||||
| == APP ==       Payment for request ID '6d2abcc9' processed successfully |  | ||||||
| == APP == info: WorkflowConsoleApp.Activities.UpdateInventoryActivity[0] |  | ||||||
| == APP ==       Checking Inventory for: Order# 6d2abcc9 for 10 Cars |  | ||||||
| == APP == info: WorkflowConsoleApp.Activities.UpdateInventoryActivity[0] |  | ||||||
| == APP ==       There are now: 90 Cars left in stock |  | ||||||
| == APP == info: WorkflowConsoleApp.Activities.NotifyActivity[0] |  | ||||||
| == APP ==       Order 6d2abcc9 has completed! |  | ||||||
| 
 |  | ||||||
| == APP == Workflow Status: Completed |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ### (Optional) Step 4: View in Zipkin |  | ||||||
| 
 |  | ||||||
| If you have Zipkin configured for Dapr locally on your machine, you can view the workflow trace spans in the Zipkin web UI (typically at `http://localhost:9411/zipkin/`). |  | ||||||
| 
 |  | ||||||
| <img src="/images/workflow-trace-spans-zipkin.png" width=800 style="padding-bottom:15px;"> |  | ||||||
| 
 |  | ||||||
| ### What happened? |  | ||||||
| 
 |  | ||||||
| When you ran `dapr run --app-id order-processor dotnet run`: |  | ||||||
| 
 |  | ||||||
| 1. A unique order ID for the workflow is generated (in the above example, `6d2abcc9`) and the workflow is scheduled. |  | ||||||
| 1. The `NotifyActivity` workflow activity sends a notification saying an order for 10 cars has been received. |  | ||||||
| 1. The `ReserveInventoryActivity` workflow activity checks the inventory data, determines if you can supply the ordered item, and responds with the number of cars in stock. |  | ||||||
| 1. Your workflow starts and notifies you of its status. |  | ||||||
| 1. The `ProcessPaymentActivity` workflow activity begins processing payment for order `6d2abcc9` and confirms if successful. |  | ||||||
| 1. The `UpdateInventoryActivity` workflow activity updates the inventory with the current available cars after the order has been processed. |  | ||||||
| 1. The `NotifyActivity` workflow activity sends a notification saying that order `6d2abcc9` has completed. |  | ||||||
| 1. The workflow terminates as completed. |  | ||||||
| 
 |  | ||||||
| #### `order-processor/Program.cs`  |  | ||||||
| 
 |  | ||||||
| In the application's program file: |  | ||||||
| - The unique workflow order ID is generated |  | ||||||
| - The workflow is scheduled |  | ||||||
| - The workflow status is retrieved |  | ||||||
| - The workflow and the workflow activities it invokes are registered |  | ||||||
| 
 |  | ||||||
| ```csharp |  | ||||||
| using Dapr.Client; |  | ||||||
| using Dapr.Workflow; |  | ||||||
| //... |  | ||||||
| 
 |  | ||||||
| { |  | ||||||
|     services.AddDaprWorkflow(options => |  | ||||||
|     { |  | ||||||
|         // Note that it's also possible to register a lambda function as the workflow |  | ||||||
|         // or activity implementation instead of a class. |  | ||||||
|         options.RegisterWorkflow<OrderProcessingWorkflow>(); |  | ||||||
| 
 |  | ||||||
|         // These are the activities that get invoked by the workflow(s). |  | ||||||
|         options.RegisterActivity<NotifyActivity>(); |  | ||||||
|         options.RegisterActivity<ReserveInventoryActivity>(); |  | ||||||
|         options.RegisterActivity<ProcessPaymentActivity>(); |  | ||||||
|         options.RegisterActivity<UpdateInventoryActivity>(); |  | ||||||
|     }); |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| //... |  | ||||||
| 
 |  | ||||||
| // Generate a unique ID for the workflow |  | ||||||
| string orderId = Guid.NewGuid().ToString()[..8]; |  | ||||||
| string itemToPurchase = "Cars"; |  | ||||||
| int ammountToPurchase = 10; |  | ||||||
| 
 |  | ||||||
| // Construct the order |  | ||||||
| OrderPayload orderInfo = new OrderPayload(itemToPurchase, 15000, ammountToPurchase); |  | ||||||
| 
 |  | ||||||
| // Start the workflow |  | ||||||
| Console.WriteLine("Starting workflow {0} purchasing {1} {2}", orderId, ammountToPurchase, itemToPurchase); |  | ||||||
| 
 |  | ||||||
| await daprClient.StartWorkflowAsync( |  | ||||||
|     workflowComponent: DaprWorkflowComponent, |  | ||||||
|     workflowName: nameof(OrderProcessingWorkflow), |  | ||||||
|     input: orderInfo, |  | ||||||
|     instanceId: orderId); |  | ||||||
| 
 |  | ||||||
| // Wait for the workflow to start and confirm the input |  | ||||||
| GetWorkflowResponse state = await daprClient.WaitForWorkflowStartAsync( |  | ||||||
|     instanceId: orderId, |  | ||||||
|     workflowComponent: DaprWorkflowComponent); |  | ||||||
| 
 |  | ||||||
| Console.WriteLine("Your workflow has started. Here is the status of the workflow: {0}", state.RuntimeStatus); |  | ||||||
| 
 |  | ||||||
| // Wait for the workflow to complete |  | ||||||
| state = await daprClient.WaitForWorkflowCompletionAsync( |  | ||||||
|     instanceId: orderId, |  | ||||||
|     workflowComponent: DaprWorkflowComponent); |  | ||||||
| 
 |  | ||||||
| Console.WriteLine("Workflow Status: {0}", state.RuntimeStatus); |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| #### `order-processor/Workflows/OrderProcessingWorkflow.cs` |  | ||||||
| 
 |  | ||||||
| In `OrderProcessingWorkflow.cs`, the workflow is defined as a class with all of its associated tasks (determined by workflow activities). |  | ||||||
| 
 |  | ||||||
| ```csharp |  | ||||||
| using Dapr.Workflow; |  | ||||||
| //... |  | ||||||
| 
 |  | ||||||
| class OrderProcessingWorkflow : Workflow<OrderPayload, OrderResult> |  | ||||||
|     { |  | ||||||
|         public override async Task<OrderResult> RunAsync(WorkflowContext context, OrderPayload order) |  | ||||||
|         { |  | ||||||
|             string orderId = context.InstanceId; |  | ||||||
| 
 |  | ||||||
|             // Notify the user that an order has come through |  | ||||||
|             await context.CallActivityAsync( |  | ||||||
|                 nameof(NotifyActivity), |  | ||||||
|                 new Notification($"Received order {orderId} for {order.Quantity} {order.Name} at ${order.TotalCost}")); |  | ||||||
| 
 |  | ||||||
|             string requestId = context.InstanceId; |  | ||||||
| 
 |  | ||||||
|             // Determine if there is enough of the item available for purchase by checking the inventory |  | ||||||
|             InventoryResult result = await context.CallActivityAsync<InventoryResult>( |  | ||||||
|                 nameof(ReserveInventoryActivity), |  | ||||||
|                 new InventoryRequest(RequestId: orderId, order.Name, order.Quantity)); |  | ||||||
| 
 |  | ||||||
|             // If there is insufficient inventory, fail and let the user know  |  | ||||||
|             if (!result.Success) |  | ||||||
|             { |  | ||||||
|                 // End the workflow here since we don't have sufficient inventory |  | ||||||
|                 await context.CallActivityAsync( |  | ||||||
|                     nameof(NotifyActivity), |  | ||||||
|                     new Notification($"Insufficient inventory for {order.Name}")); |  | ||||||
|                 return new OrderResult(Processed: false); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             // There is enough inventory available so the user can purchase the item(s). Process their payment |  | ||||||
|             await context.CallActivityAsync( |  | ||||||
|                 nameof(ProcessPaymentActivity), |  | ||||||
|                 new PaymentRequest(RequestId: orderId, order.Name, order.Quantity, order.TotalCost)); |  | ||||||
| 
 |  | ||||||
|             try |  | ||||||
|             { |  | ||||||
|                 // There is enough inventory available so the user can purchase the item(s). Process their payment |  | ||||||
|                 await context.CallActivityAsync( |  | ||||||
|                     nameof(UpdateInventoryActivity), |  | ||||||
|                     new PaymentRequest(RequestId: orderId, order.Name, order.Quantity, order.TotalCost));                 |  | ||||||
|             } |  | ||||||
|             catch (TaskFailedException) |  | ||||||
|             { |  | ||||||
|                 // Let them know their payment was processed |  | ||||||
|                 await context.CallActivityAsync( |  | ||||||
|                     nameof(NotifyActivity), |  | ||||||
|                     new Notification($"Order {orderId} Failed! You are now getting a refund")); |  | ||||||
|                 return new OrderResult(Processed: false); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             // Let them know their payment was processed |  | ||||||
|             await context.CallActivityAsync( |  | ||||||
|                 nameof(NotifyActivity), |  | ||||||
|                 new Notification($"Order {orderId} has completed!")); |  | ||||||
| 
 |  | ||||||
|             // End the workflow with a success result |  | ||||||
|             return new OrderResult(Processed: true); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| #### `order-processor/Activities` directory |  | ||||||
| 
 |  | ||||||
| The `Activities` directory holds the four workflow activities used by the workflow, defined in the following files: |  | ||||||
| - `NotifyActivity.cs` |  | ||||||
| - `ReserveInventoryActivity.cs` |  | ||||||
| - `ProcessPaymentActivity.cs` |  | ||||||
| - `UpdateInventoryActivity.cs` |  | ||||||
| 
 |  | ||||||
| {{% /codetab %}} |  | ||||||
| 
 |  | ||||||
|  <!-- Python --> |  | ||||||
| {{% codetab %}} | {{% codetab %}} | ||||||
| 
 | 
 | ||||||
| The `order-processor` console app starts and manages the `order_processing_workflow`, which simulates purchasing items from a store. The workflow consists of five unique workflow activities, or tasks: | The `order-processor` console app starts and manages the `order_processing_workflow`, which simulates purchasing items from a store. The workflow consists of five unique workflow activities, or tasks: | ||||||
|  | @ -494,6 +261,334 @@ In `workflow.py`, the workflow is defined as a class with all of its associated | ||||||
| ``` | ``` | ||||||
| {{% /codetab %}} | {{% /codetab %}} | ||||||
| 
 | 
 | ||||||
|  |  <!-- .NET --> | ||||||
|  | {{% codetab %}} | ||||||
|  | 
 | ||||||
|  | The `order-processor` console app starts and manages the lifecycle of an order processing workflow that stores and retrieves data in a state store. The workflow consists of four workflow activities, or tasks: | ||||||
|  | - `NotifyActivity`: Utilizes a logger to print out messages throughout the workflow | ||||||
|  | - `ReserveInventoryActivity`: Checks the state store to ensure that there is enough inventory for the purchase | ||||||
|  | - `ProcessPaymentActivity`: Processes and authorizes the payment | ||||||
|  | - `UpdateInventoryActivity`: Removes the requested items from the state store and updates the store with the new remaining inventory value | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ### Step 1: Pre-requisites | ||||||
|  | 
 | ||||||
|  | For this example, you will need: | ||||||
|  | 
 | ||||||
|  | - [Dapr CLI and initialized environment](https://docs.dapr.io/getting-started). | ||||||
|  | - [.NET SDK or .NET 6 SDK installed](https://dotnet.microsoft.com/download). | ||||||
|  | <!-- IGNORE_LINKS --> | ||||||
|  | - [Docker Desktop](https://www.docker.com/products/docker-desktop) | ||||||
|  | <!-- END_IGNORE --> | ||||||
|  | 
 | ||||||
|  | ### Step 2: Set up the environment | ||||||
|  | 
 | ||||||
|  | Clone the [sample provided in the Quickstarts repo](https://github.com/dapr/quickstarts/tree/master/workflows). | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | git clone https://github.com/dapr/quickstarts.git | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | In a new terminal window, navigate to the `order-processor` directory: | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | cd workflows/csharp/sdk/order-processor | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ### Step 3: Run the order processor app | ||||||
|  | 
 | ||||||
|  | In the terminal, start the order processor app alongside a Dapr sidecar: | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | dapr run --app-id order-processor dotnet run | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | This starts the `order-processor` app with unique workflow ID and runs the workflow activities.  | ||||||
|  | 
 | ||||||
|  | Expected output: | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | == APP == Starting workflow 6d2abcc9 purchasing 10 Cars | ||||||
|  | 
 | ||||||
|  | == APP == info: Microsoft.DurableTask.Client.Grpc.GrpcDurableTaskClient[40] | ||||||
|  | == APP ==       Scheduling new OrderProcessingWorkflow orchestration with instance ID '6d2abcc9' and 47 bytes of input data. | ||||||
|  | == APP == info: WorkflowConsoleApp.Activities.NotifyActivity[0] | ||||||
|  | == APP ==       Received order 6d2abcc9 for 10 Cars at $15000 | ||||||
|  | == APP == info: WorkflowConsoleApp.Activities.ReserveInventoryActivity[0] | ||||||
|  | == APP ==       Reserving inventory for order 6d2abcc9 of 10 Cars | ||||||
|  | == APP == info: WorkflowConsoleApp.Activities.ReserveInventoryActivity[0] | ||||||
|  | == APP ==       There are: 100, Cars available for purchase | ||||||
|  | 
 | ||||||
|  | == APP == Your workflow has started. Here is the status of the workflow: Dapr.Workflow.WorkflowState | ||||||
|  | 
 | ||||||
|  | == APP == info: WorkflowConsoleApp.Activities.ProcessPaymentActivity[0] | ||||||
|  | == APP ==       Processing payment: 6d2abcc9 for 10 Cars at $15000 | ||||||
|  | == APP == info: WorkflowConsoleApp.Activities.ProcessPaymentActivity[0] | ||||||
|  | == APP ==       Payment for request ID '6d2abcc9' processed successfully | ||||||
|  | == APP == info: WorkflowConsoleApp.Activities.UpdateInventoryActivity[0] | ||||||
|  | == APP ==       Checking Inventory for: Order# 6d2abcc9 for 10 Cars | ||||||
|  | == APP == info: WorkflowConsoleApp.Activities.UpdateInventoryActivity[0] | ||||||
|  | == APP ==       There are now: 90 Cars left in stock | ||||||
|  | == APP == info: WorkflowConsoleApp.Activities.NotifyActivity[0] | ||||||
|  | == APP ==       Order 6d2abcc9 has completed! | ||||||
|  | 
 | ||||||
|  | == APP == Workflow Status: Completed | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ### (Optional) Step 4: View in Zipkin | ||||||
|  | 
 | ||||||
|  | If you have Zipkin configured for Dapr locally on your machine, you can view the workflow trace spans in the Zipkin web UI (typically at `http://localhost:9411/zipkin/`). | ||||||
|  | 
 | ||||||
|  | <img src="/images/workflow-trace-spans-zipkin.png" width=800 style="padding-bottom:15px;"> | ||||||
|  | 
 | ||||||
|  | ### What happened? | ||||||
|  | 
 | ||||||
|  | When you ran `dapr run --app-id order-processor dotnet run`: | ||||||
|  | 
 | ||||||
|  | 1. A unique order ID for the workflow is generated (in the above example, `6d2abcc9`) and the workflow is scheduled. | ||||||
|  | 1. The `NotifyActivity` workflow activity sends a notification saying an order for 10 cars has been received. | ||||||
|  | 1. The `ReserveInventoryActivity` workflow activity checks the inventory data, determines if you can supply the ordered item, and responds with the number of cars in stock. | ||||||
|  | 1. Your workflow starts and notifies you of its status. | ||||||
|  | 1. The `ProcessPaymentActivity` workflow activity begins processing payment for order `6d2abcc9` and confirms if successful. | ||||||
|  | 1. The `UpdateInventoryActivity` workflow activity updates the inventory with the current available cars after the order has been processed. | ||||||
|  | 1. The `NotifyActivity` workflow activity sends a notification saying that order `6d2abcc9` has completed. | ||||||
|  | 1. The workflow terminates as completed. | ||||||
|  | 
 | ||||||
|  | #### `order-processor/Program.cs`  | ||||||
|  | 
 | ||||||
|  | In the application's program file: | ||||||
|  | - The unique workflow order ID is generated | ||||||
|  | - The workflow is scheduled | ||||||
|  | - The workflow status is retrieved | ||||||
|  | - The workflow and the workflow activities it invokes are registered | ||||||
|  | 
 | ||||||
|  | ```csharp | ||||||
|  | using Dapr.Client; | ||||||
|  | using Dapr.Workflow; | ||||||
|  | //... | ||||||
|  | 
 | ||||||
|  | { | ||||||
|  |     services.AddDaprWorkflow(options => | ||||||
|  |     { | ||||||
|  |         // Note that it's also possible to register a lambda function as the workflow | ||||||
|  |         // or activity implementation instead of a class. | ||||||
|  |         options.RegisterWorkflow<OrderProcessingWorkflow>(); | ||||||
|  | 
 | ||||||
|  |         // These are the activities that get invoked by the workflow(s). | ||||||
|  |         options.RegisterActivity<NotifyActivity>(); | ||||||
|  |         options.RegisterActivity<ReserveInventoryActivity>(); | ||||||
|  |         options.RegisterActivity<ProcessPaymentActivity>(); | ||||||
|  |         options.RegisterActivity<UpdateInventoryActivity>(); | ||||||
|  |     }); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | //... | ||||||
|  | 
 | ||||||
|  | // Generate a unique ID for the workflow | ||||||
|  | string orderId = Guid.NewGuid().ToString()[..8]; | ||||||
|  | string itemToPurchase = "Cars"; | ||||||
|  | int ammountToPurchase = 10; | ||||||
|  | 
 | ||||||
|  | // Construct the order | ||||||
|  | OrderPayload orderInfo = new OrderPayload(itemToPurchase, 15000, ammountToPurchase); | ||||||
|  | 
 | ||||||
|  | // Start the workflow | ||||||
|  | Console.WriteLine("Starting workflow {0} purchasing {1} {2}", orderId, ammountToPurchase, itemToPurchase); | ||||||
|  | 
 | ||||||
|  | await daprClient.StartWorkflowAsync( | ||||||
|  |     workflowComponent: DaprWorkflowComponent, | ||||||
|  |     workflowName: nameof(OrderProcessingWorkflow), | ||||||
|  |     input: orderInfo, | ||||||
|  |     instanceId: orderId); | ||||||
|  | 
 | ||||||
|  | // Wait for the workflow to start and confirm the input | ||||||
|  | GetWorkflowResponse state = await daprClient.WaitForWorkflowStartAsync( | ||||||
|  |     instanceId: orderId, | ||||||
|  |     workflowComponent: DaprWorkflowComponent); | ||||||
|  | 
 | ||||||
|  | Console.WriteLine("Your workflow has started. Here is the status of the workflow: {0}", state.RuntimeStatus); | ||||||
|  | 
 | ||||||
|  | // Wait for the workflow to complete | ||||||
|  | state = await daprClient.WaitForWorkflowCompletionAsync( | ||||||
|  |     instanceId: orderId, | ||||||
|  |     workflowComponent: DaprWorkflowComponent); | ||||||
|  | 
 | ||||||
|  | Console.WriteLine("Workflow Status: {0}", state.RuntimeStatus); | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | #### `order-processor/Workflows/OrderProcessingWorkflow.cs` | ||||||
|  | 
 | ||||||
|  | In `OrderProcessingWorkflow.cs`, the workflow is defined as a class with all of its associated tasks (determined by workflow activities). | ||||||
|  | 
 | ||||||
|  | ```csharp | ||||||
|  | using Dapr.Workflow; | ||||||
|  | //... | ||||||
|  | 
 | ||||||
|  | class OrderProcessingWorkflow : Workflow<OrderPayload, OrderResult> | ||||||
|  |     { | ||||||
|  |         public override async Task<OrderResult> RunAsync(WorkflowContext context, OrderPayload order) | ||||||
|  |         { | ||||||
|  |             string orderId = context.InstanceId; | ||||||
|  | 
 | ||||||
|  |             // Notify the user that an order has come through | ||||||
|  |             await context.CallActivityAsync( | ||||||
|  |                 nameof(NotifyActivity), | ||||||
|  |                 new Notification($"Received order {orderId} for {order.Quantity} {order.Name} at ${order.TotalCost}")); | ||||||
|  | 
 | ||||||
|  |             string requestId = context.InstanceId; | ||||||
|  | 
 | ||||||
|  |             // Determine if there is enough of the item available for purchase by checking the inventory | ||||||
|  |             InventoryResult result = await context.CallActivityAsync<InventoryResult>( | ||||||
|  |                 nameof(ReserveInventoryActivity), | ||||||
|  |                 new InventoryRequest(RequestId: orderId, order.Name, order.Quantity)); | ||||||
|  | 
 | ||||||
|  |             // If there is insufficient inventory, fail and let the user know  | ||||||
|  |             if (!result.Success) | ||||||
|  |             { | ||||||
|  |                 // End the workflow here since we don't have sufficient inventory | ||||||
|  |                 await context.CallActivityAsync( | ||||||
|  |                     nameof(NotifyActivity), | ||||||
|  |                     new Notification($"Insufficient inventory for {order.Name}")); | ||||||
|  |                 return new OrderResult(Processed: false); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // There is enough inventory available so the user can purchase the item(s). Process their payment | ||||||
|  |             await context.CallActivityAsync( | ||||||
|  |                 nameof(ProcessPaymentActivity), | ||||||
|  |                 new PaymentRequest(RequestId: orderId, order.Name, order.Quantity, order.TotalCost)); | ||||||
|  | 
 | ||||||
|  |             try | ||||||
|  |             { | ||||||
|  |                 // There is enough inventory available so the user can purchase the item(s). Process their payment | ||||||
|  |                 await context.CallActivityAsync( | ||||||
|  |                     nameof(UpdateInventoryActivity), | ||||||
|  |                     new PaymentRequest(RequestId: orderId, order.Name, order.Quantity, order.TotalCost));                 | ||||||
|  |             } | ||||||
|  |             catch (TaskFailedException) | ||||||
|  |             { | ||||||
|  |                 // Let them know their payment was processed | ||||||
|  |                 await context.CallActivityAsync( | ||||||
|  |                     nameof(NotifyActivity), | ||||||
|  |                     new Notification($"Order {orderId} Failed! You are now getting a refund")); | ||||||
|  |                 return new OrderResult(Processed: false); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // Let them know their payment was processed | ||||||
|  |             await context.CallActivityAsync( | ||||||
|  |                 nameof(NotifyActivity), | ||||||
|  |                 new Notification($"Order {orderId} has completed!")); | ||||||
|  | 
 | ||||||
|  |             // End the workflow with a success result | ||||||
|  |             return new OrderResult(Processed: true); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | #### `order-processor/Activities` directory | ||||||
|  | 
 | ||||||
|  | The `Activities` directory holds the four workflow activities used by the workflow, defined in the following files: | ||||||
|  | - `NotifyActivity.cs` | ||||||
|  | - `ReserveInventoryActivity.cs` | ||||||
|  | - `ProcessPaymentActivity.cs` | ||||||
|  | - `UpdateInventoryActivity.cs` | ||||||
|  | 
 | ||||||
|  | {{% /codetab %}} | ||||||
|  | 
 | ||||||
|  |  <!-- Java --> | ||||||
|  | {{% codetab %}} | ||||||
|  | 
 | ||||||
|  | The `order-processor` console app starts and manages the lifecycle of an order processing workflow that stores and retrieves data in a state store. The workflow consists of four workflow activities, or tasks: | ||||||
|  | -  | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | ### Step 1: Pre-requisites | ||||||
|  | 
 | ||||||
|  | For this example, you will need: | ||||||
|  | 
 | ||||||
|  | - [Dapr CLI and initialized environment](https://docs.dapr.io/getting-started). | ||||||
|  | - Java JDK 11 (or greater): | ||||||
|  |   - [Oracle JDK](https://www.oracle.com/java/technologies/downloads), or | ||||||
|  |   - OpenJDK | ||||||
|  | - [Apache Maven](https://maven.apache.org/install.html), version 3.x. | ||||||
|  | <!-- IGNORE_LINKS --> | ||||||
|  | - [Docker Desktop](https://www.docker.com/products/docker-desktop) | ||||||
|  | <!-- END_IGNORE --> | ||||||
|  | 
 | ||||||
|  | ### Step 2: Set up the environment | ||||||
|  | 
 | ||||||
|  | Clone the [sample provided in the Quickstarts repo](https://github.com/dapr/quickstarts/tree/master/workflows). | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | git clone https://github.com/dapr/quickstarts.git | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | In a new terminal window, navigate to the `order-processor` directory: | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | need | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ### Step 3: Run the order processor app | ||||||
|  | 
 | ||||||
|  | In the terminal, start the order processor app alongside a Dapr sidecar: | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | need | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | This starts the `order-processor` app with unique workflow ID and runs the workflow activities.  | ||||||
|  | 
 | ||||||
|  | Expected output: | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | need | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ### (Optional) Step 4: View in Zipkin | ||||||
|  | 
 | ||||||
|  | If you have Zipkin configured for Dapr locally on your machine, you can view the workflow trace spans in the Zipkin web UI (typically at `http://localhost:9411/zipkin/`). | ||||||
|  | 
 | ||||||
|  | <img src="/images/workflow-trace-spans-zipkin.png" width=800 style="padding-bottom:15px;"> | ||||||
|  | 
 | ||||||
|  | ### What happened? | ||||||
|  | 
 | ||||||
|  | When you ran `need`: | ||||||
|  | 
 | ||||||
|  | 1. A unique order ID for the workflow is generated (in the above example, `need`) and the workflow is scheduled. | ||||||
|  | 1. The `need` workflow activity sends a notification saying an order for 10 cars has been received. | ||||||
|  | 1. The `need` workflow activity checks the inventory data, determines if you can supply the ordered item, and responds with the number of cars in stock. | ||||||
|  | 1. Your workflow starts and notifies you of its status. | ||||||
|  | 1. The `need` workflow activity begins processing payment for order `need` and confirms if successful. | ||||||
|  | 1. The `need` workflow activity updates the inventory with the current available cars after the order has been processed. | ||||||
|  | 1. The `need` workflow activity sends a notification saying that order `need` has completed. | ||||||
|  | 1. The workflow terminates as completed. | ||||||
|  | 
 | ||||||
|  | #### `order-processor/... need`  | ||||||
|  | 
 | ||||||
|  | In the application's program file: | ||||||
|  | - The unique workflow order ID is generated | ||||||
|  | - The workflow is scheduled | ||||||
|  | - The workflow status is retrieved | ||||||
|  | - The workflow and the workflow activities it invokes are registered | ||||||
|  | 
 | ||||||
|  | ```java | ||||||
|  | need | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | #### `order-processor/... need` | ||||||
|  | 
 | ||||||
|  | In `need`, the workflow is defined as a class with all of its associated tasks (determined by workflow activities). | ||||||
|  | 
 | ||||||
|  | ```java | ||||||
|  | need | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | #### `order-processor/... need` directory | ||||||
|  | 
 | ||||||
|  | The `Activities` directory holds the four workflow activities used by the workflow, defined in the following files: | ||||||
|  | - `need` | ||||||
|  | 
 | ||||||
|  | {{% /codetab %}} | ||||||
| 
 | 
 | ||||||
| {{< /tabs >}} | {{< /tabs >}} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue