update quickstart, start updating patterns

Signed-off-by: Hannah Hunter <hannahhunter@microsoft.com>
This commit is contained in:
Hannah Hunter 2024-02-14 14:02:09 -05:00
parent 0f50934b63
commit c5ee2810a3
2 changed files with 53 additions and 187 deletions

View File

@ -164,7 +164,49 @@ public class ChainWorkflow extends Workflow {
<!--go-->
```go
func TaskChainWorkflow(ctx *workflow.WorkflowContext) (any, error) {
var input int
if err := ctx.GetInput(&input); err != nil {
return "", err
}
var result1 int
if err := ctx.CallActivity(Step1, workflow.ActivityInput(input)).Await(&result1); err != nil {
return nil, err
}
var result2 int
if err := ctx.CallActivity(Step1, workflow.ActivityInput(input)).Await(&result2); err != nil {
return nil, err
}
var result3 int
if err := ctx.CallActivity(Step1, workflow.ActivityInput(input)).Await(&result3); err != nil {
return nil, err
}
return []int{result1, result2, result3}, nil
}
func Step1(ctx workflow.ActivityContext) (any, error) {
var input int
if err := ctx.GetInput(&input); err != nil {
return "", err
}
fmt.Printf("Step 1: Received input: %s", input)
return input + 1, nil
}
func Step2(ctx workflow.ActivityContext) (any, error) {
var input int
if err := ctx.GetInput(&input); err != nil {
return "", err
}
fmt.Printf("Step 2: Received input: %s", input)
return input * 2, nil
}
func Step3(ctx workflow.ActivityContext) (any, error) {
var input int
if err := ctx.GetInput(&input); err != nil {
return "", err
}
fmt.Printf("Step 3: Received input: %s", input)
return int(math.Pow(float64(input), 2)), nil
}
```
{{% /codetab %}}

View File

@ -20,6 +20,7 @@ In this guide, you'll:
<img src="/images/workflow-quickstart-overview.png" width=800 style="padding-bottom:15px;">
Select your preferred language-specific Dapr SDK before proceeding with the Quickstart.
{{< tabs "Python" ".NET" "Java" "Go" >}}
@ -68,14 +69,12 @@ pip3 install -r requirements.txt
### Step 3: Run the order processor app
In the terminal, start the order processor app alongside a Dapr sidecar:
In the terminal, start the order processor app alongside a Dapr sidecar using [Multi-App Run]({{< ref multi-app-dapr-run >}}):
```bash
dapr run --app-id order-processor --resources-path ../../../components/ -- python3 app.py
dapr run -f .
```
> **Note:** Since Python3.exe is not defined in Windows, you may need to use `python app.py` instead of `python3 app.py`.
This starts the `order-processor` app with unique workflow ID and runs the workflow activities.
Expected output:
@ -303,10 +302,10 @@ 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:
In the terminal, start the order processor app alongside a Dapr sidecar using [Multi-App Run]({{< ref multi-app-dapr-run >}}):
```bash
dapr run --app-id order-processor dotnet run
dapr run -f .
```
This starts the `order-processor` app with unique workflow ID and runs the workflow activities.
@ -559,10 +558,10 @@ mvn clean install
### Step 3: Run the order processor app
In the terminal, start the order processor app alongside a Dapr sidecar:
In the terminal, start the order processor app alongside a Dapr sidecar using [Multi-App Run]({{< ref multi-app-dapr-run >}}):
```bash
dapr run --app-id WorkflowConsoleApp --resources-path ../../../components/ --dapr-grpc-port 50001 -- java -jar target/OrderProcessingService-0.0.1-SNAPSHOT.jar io.dapr.quickstarts.workflows.WorkflowConsoleApp
dapr run -f .
```
This starts the `order-processor` app with unique workflow ID and runs the workflow activities.
@ -856,7 +855,7 @@ The `Activities` directory holds the four workflow activities used by the workfl
{{% codetab %}}
The `order-processor` console app starts and manages the `OrderProcessingWorkflow`, 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 `OrderProcessingWorkflow` workflow, which simulates purchasing items from a store. The workflow consists of five unique workflow activities, or tasks:
- `NotifyActivity`: Utilizes a logger to print out messages throughout the workflow. These messages notify you when:
- You have insufficient inventory
@ -890,15 +889,9 @@ In a new terminal window, navigate to the `order-processor` directory:
cd workflows/go/sdk/order-processor
```
Install the Dapr Go SDK dependencies:
```bash
go build .
```
### Step 3: Run the order processor app
In the terminal, start the order processor app alongside a Dapr sidecar:
In the terminal, start the order processor app alongside a Dapr sidecar using [Multi-App Run]({{< ref multi-app-dapr-run >}}):
```bash
dapr run -f .
@ -1097,177 +1090,8 @@ func restockInventory(daprClient client.Client, inventory []InventoryItem) error
}
```
#### `order-processor/workflow.go`
Meanwhile, the `OrderProcessingWorkflow` and its activities are defined as methods in [`workflow.go`](https://github.com/dapr/quickstarts/workflows/go/sdk/order-processor/workflow.go)
In `main.go`, the workflow is defined as a method with all of its associated tasks (determined by workflow activities).
```go
// OrderProcessingWorkflow is the main workflow for orchestrating activities in the order process.
func OrderProcessingWorkflow(ctx *workflow.WorkflowContext) (any, error) {
orderID := ctx.InstanceID()
var orderPayload OrderPayload
if err := ctx.GetInput(&orderPayload); err != nil {
return nil, err
}
if err := ctx.CallActivity(NotifyActivity, workflow.ActivityInput(Notification{Message: fmt.Sprintf("Received order %s for %d %s - $%d", orderID, orderPayload.Quantity, orderPayload.ItemName, orderPayload.TotalCost)})).Await(nil); err != nil {
return OrderResult{Processed: false}, err
}
var verifyInventoryResult InventoryResult
if err := ctx.CallActivity(VerifyInventoryActivity, workflow.ActivityInput(InventoryRequest{
RequestID: orderID,
ItemName: orderPayload.ItemName,
Quantity: orderPayload.Quantity,
})).Await(&verifyInventoryResult); err != nil {
return OrderResult{Processed: false}, err
}
if !verifyInventoryResult.Success {
if err := ctx.CallActivity(NotifyActivity, workflow.ActivityInput(Notification{Message: fmt.Sprintf("Insufficient inventory for %s", orderPayload.ItemName)})).Await(nil); err != nil {
return OrderResult{Processed: false}, err
}
}
if orderPayload.TotalCost > 50000 {
var approvalRequired ApprovalRequired
if err := ctx.CallActivity(RequestApprovalActivity, workflow.ActivityInput(orderPayload)).Await(&approvalRequired); err != nil {
return OrderResult{Processed: false}, err
}
if err := ctx.WaitForExternalEvent("manager_approval", time.Second*200).Await(nil); err != nil {
return OrderResult{Processed: false}, err
}
// TODO: Confirm timeout flow - this will be in the form of an error.
if approvalRequired.Approval {
if err := ctx.CallActivity(NotifyActivity, workflow.ActivityInput(Notification{Message: fmt.Sprintf("Payment for order %s has been approved!", orderID)})).Await(nil); err != nil {
log.Printf("failed to notify of a successful order: %v\n", err)
}
} else {
if err := ctx.CallActivity(NotifyActivity, workflow.ActivityInput(Notification{Message: fmt.Sprintf("Payment for order %s has been rejected!", orderID)})).Await(nil); err != nil {
log.Printf("failed to notify of an unsuccessful order :%v\n", err)
}
return OrderResult{Processed: false}, nil
}
}
if err := ctx.CallActivity(ProcessPaymentActivity, workflow.ActivityInput(PaymentRequest{
RequestID: orderID,
ItemBeingPurchased: orderPayload.ItemName,
Amount: orderPayload.TotalCost,
Quantity: orderPayload.Quantity,
})).Await(nil); err != nil {
if err := ctx.CallActivity(NotifyActivity, workflow.ActivityInput(Notification{Message: fmt.Sprintf("Order %s failed!", orderID)})).Await(nil); err != nil {
log.Printf("failed to notify of a failed order: %v", err)
}
return OrderResult{Processed: false}, err
}
if err := ctx.CallActivity(UpdateInventoryActivity, workflow.ActivityInput(PaymentRequest{RequestID: orderID, ItemBeingPurchased: orderPayload.ItemName, Amount: orderPayload.TotalCost, Quantity: orderPayload.Quantity})).Await(nil); err != nil {
if err := ctx.CallActivity(NotifyActivity, workflow.ActivityInput(Notification{Message: fmt.Sprintf("Order %s failed!", orderID)})).Await(nil); err != nil {
log.Printf("failed to notify of a failed order: %v", err)
}
return OrderResult{Processed: false}, err
}
if err := ctx.CallActivity(NotifyActivity, workflow.ActivityInput(Notification{Message: fmt.Sprintf("Order %s has completed!", orderID)})).Await(nil); err != nil {
log.Printf("failed to notify of a successful order: %v", err)
}
return OrderResult{Processed: true}, nil
}
// NotifyActivity outputs a notification message
func NotifyActivity(ctx workflow.ActivityContext) (any, error) {
var input Notification
if err := ctx.GetInput(&input); err != nil {
return "", err
}
fmt.Printf("NotifyActivity: %s\n", input.Message)
return nil, nil
}
// ProcessPaymentActivity is used to process a payment
func ProcessPaymentActivity(ctx workflow.ActivityContext) (any, error) {
var input PaymentRequest
if err := ctx.GetInput(&input); err != nil {
return "", err
}
fmt.Printf("ProcessPaymentActivity: %s for %d - %s (%dUSD)\n", input.RequestID, input.Quantity, input.ItemBeingPurchased, input.Amount)
return nil, nil
}
// VerifyInventoryActivity is used to verify if an item is available in the inventory
func VerifyInventoryActivity(ctx workflow.ActivityContext) (any, error) {
var input InventoryRequest
if err := ctx.GetInput(&input); err != nil {
return nil, err
}
fmt.Printf("VerifyInventoryActivity: Verifying inventory for order %s of %d %s\n", input.RequestID, input.Quantity, input.ItemName)
dClient, err := client.NewClient()
if err != nil {
return nil, err
}
item, err := dClient.GetState(context.Background(), stateStoreName, input.ItemName, nil)
if err != nil {
return nil, err
}
if item == nil {
return InventoryResult{
Success: false,
InventoryItem: InventoryItem{},
}, nil
}
var result InventoryItem
if err := json.Unmarshal(item.Value, &result); err != nil {
log.Fatalf("failed to parse inventory result %v", err)
}
fmt.Printf("VerifyInventoryActivity: There are %d %s available for purchase\n", result.Quantity, result.ItemName)
if result.Quantity >= input.Quantity {
return InventoryResult{Success: true, InventoryItem: result}, nil
}
return InventoryResult{Success: false, InventoryItem: InventoryItem{}}, nil
}
// UpdateInventoryActivity modifies the inventory.
func UpdateInventoryActivity(ctx workflow.ActivityContext) (any, error) {
var input PaymentRequest
if err := ctx.GetInput(&input); err != nil {
return nil, err
}
fmt.Printf("UpdateInventoryActivity: Checking Inventory for order %s for %d * %s\n", input.RequestID, input.Quantity, input.ItemBeingPurchased)
dClient, err := client.NewClient()
if err != nil {
return nil, err
}
item, err := dClient.GetState(context.Background(), stateStoreName, input.ItemBeingPurchased, nil)
if err != nil {
return nil, err
}
var result InventoryItem
err = json.Unmarshal(item.Value, &result)
if err != nil {
return nil, err
}
newQuantity := result.Quantity - input.Quantity
if newQuantity < 0 {
return nil, fmt.Errorf("insufficient inventory for: %s", input.ItemBeingPurchased)
}
result.Quantity = newQuantity
newState, err := json.Marshal(result)
if err != nil {
log.Fatalf("failed to marshal new state: %v", err)
}
dClient.SaveState(context.Background(), stateStoreName, input.ItemBeingPurchased, newState, nil)
fmt.Printf("UpdateInventoryActivity: There are now %d %s left in stock\n", result.Quantity, result.ItemName)
return InventoryResult{Success: true, InventoryItem: result}, nil
}
// RequestApprovalActivity requests approval for the order
func RequestApprovalActivity(ctx workflow.ActivityContext) (any, error) {
var input OrderPayload
if err := ctx.GetInput(&input); err != nil {
return nil, err
}
fmt.Printf("RequestApprovalActivity: Requesting approval for payment of %dUSD for %d %s\n", input.TotalCost, input.Quantity, input.ItemName)
return ApprovalRequired{Approval: true}, nil
}
```
{{% /codetab %}}