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. | ||||
| 
 | ||||
| {{< 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 %}} | ||||
| 
 | ||||
|  | @ -102,29 +120,67 @@ public class ProcessPaymentActivity : WorkflowActivity<PaymentRequest, object> | |||
| 
 | ||||
| {{% 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 | ||||
| def hello_act(ctx: WorkflowActivityContext, input): | ||||
|     global counter | ||||
|     counter += input | ||||
|     print(f'New counter value is: {counter}!', flush=True) | ||||
| The activities called in the example below are: | ||||
| - `need`: Receive notification of a new order. | ||||
| 
 | ||||
| ### [activity] | ||||
| 
 | ||||
| ```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 %}} | ||||
| 
 | ||||
| 
 | ||||
| {{< /tabs >}} | ||||
| 
 | ||||
| ## Write the 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 %}} | ||||
| 
 | ||||
|  | @ -171,21 +227,15 @@ The `OrderProcessingWorkflow` class is derived from a base class called `Workflo | |||
| 
 | ||||
| {{% 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 | ||||
| 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) | ||||
| ```java | ||||
| todo | ||||
| ``` | ||||
| 
 | ||||
| [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 %}} | ||||
|  | @ -196,78 +246,7 @@ def hello_world_wf(ctx: DaprWorkflowContext, input): | |||
| 
 | ||||
| Finally, compose the application using the workflow. | ||||
| 
 | ||||
| {{< tabs ".NET" Python >}} | ||||
| 
 | ||||
| {{% 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 %}} | ||||
| {{< tabs Python ".NET" Java >}} | ||||
| 
 | ||||
| {{% 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 %}} | ||||
| 
 | ||||
| 
 | ||||
|  | @ -377,5 +441,6 @@ Now that you've authored a workflow, learn how to manage it. | |||
| - [Workflow overview]({{< ref workflow-overview.md >}}) | ||||
| - [Workflow API reference]({{< ref workflow_api.md >}}) | ||||
| - 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) | ||||
|   - [.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 >}}). | ||||
| 
 | ||||
| {{< tabs ".NET" Python 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 %}} | ||||
| {{< tabs Python ".NET" Java HTTP >}} | ||||
| 
 | ||||
| <!--Python--> | ||||
| {{% codetab %}} | ||||
|  | @ -95,6 +59,53 @@ d.terminate_workflow(instance_id=instanceId, workflow_component=workflowComponen | |||
| 
 | ||||
| {{% /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--> | ||||
| {{% codetab %}} | ||||
|  | @ -172,6 +183,8 @@ Learn more about these HTTP calls in the [workflow API reference guide]({{< ref | |||
| ## Next steps | ||||
| - [Try out the Workflow quickstart]({{< ref workflow-quickstart.md >}}) | ||||
| - 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) | ||||
|   - [.NET example](https://github.com/dapr/dotnet-sdk/tree/master/examples/Workflow) | ||||
|   - [Java example](todo) | ||||
| 
 | ||||
| - [Workflow API reference]({{< ref workflow_api.md >}}) | ||||
|  |  | |||
|  | @ -83,9 +83,9 @@ You can use the following SDKs to author a workflow. | |||
| 
 | ||||
| | 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) | | ||||
| 
 | ||||
| | .NET | [Dapr.Workflow](https://www.nuget.org/profiles/dapr.io) | | ||||
| | Java | need | | ||||
| 
 | ||||
| ## Try out workflows | ||||
| 
 | ||||
|  | @ -96,8 +96,9 @@ Want to put workflows to the test? Walk through the following quickstart and tut | |||
| | 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 .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 .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 | ||||
|  |  | |||
|  | @ -21,240 +21,7 @@ In this guide, you'll: | |||
| <img src="/images/workflow-quickstart-overview.png" width=800 style="padding-bottom:15px;"> | ||||
| 
 | ||||
| 
 | ||||
| {{< tabs ".NET" "Python" >}} | ||||
| 
 | ||||
|  <!-- .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 %}} | ||||
| {{< tabs "Python" ".NET" "Java" >}} | ||||
| 
 | ||||
| <!-- Python --> | ||||
| {{% codetab %}} | ||||
|  | @ -494,6 +261,334 @@ In `workflow.py`, the workflow is defined as a class with all of its associated | |||
| ``` | ||||
| {{% /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 >}} | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue