Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Grant-onboarding #12

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 20 additions & 10 deletions exercises/querying-workflows/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ the complete version in the `solution` subdirectory.

In this part of the exercise, you will define your Query.

1. Edit the `workflow.go` file. You will use the `workflow.SetQueryHandler()` to add Query handling to your Workflow. This can be done anywhere inside of the `Workflow()` function. In this case, you'll add a query to return the Workflow's `currentState`, so it makes sense to initialize the `currentState` variable as you go along. Note that this is the same Workflow from the previous exercise, so it is designed to wait for a Signal after starting.
1. Edit the `workflow.go` file.

You will use the `workflow.SetQueryHandler()` to add Query handling to your Workflow. This can be done anywhere inside of the `Workflow()` function. In this case, you'll add a query to return the Workflow's `currentState`, which you'll modify as the Workflow progresses. Note that this is the same Workflow from the previous exercise, so it is designed to wait for a Signal after starting.

Comment on lines -19 to +22
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tom suggested to me one time to separate prose from instruction/commands. I tried to do that here -- totally up to you on whether or not to keep it

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just adding a linebreak is a pretty reasonable way of doing that imo! I'd previously rejected suggestions along these lines that distorted the number of actual steps there were, but this works fine. Thanks!

2. Set up two string variables, `currentState := "started"` and `queryType := "current_state"`. One of these will contain the type of your Query, which will not change. The other will contain the `currentState` that is progressively updated and will be returned by the Query.
3. Next, add the `workflow.SetQueryHandler()` function with the necessary error handling:

Expand All @@ -30,8 +33,10 @@ if err != nil {
}
```

4. Finally, update `currentState` again after that block of code, to something like "waiting for signal". This is the state that the Workflow will be waiting at when we query it.
5. Save the file.
4. Update `currentState` again after that block of code, to something like "waiting for signal". This is the state that the Workflow will be waiting at when we query it.
5. Finally, update `currentState` to something like `"Workflow Complete"`
after the Activity has completed successfully near where the Workflow completion is logged.
6. Save the file.
Comment on lines -33 to +39
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added this note to change to add a statement for workflow complete. It used to be in part E, but I just moved it here. I think it's easier to have it here because I think if it's in E, the user needs to restart workers etc


## Part B: Performing a Query from a Client

Expand All @@ -41,7 +46,7 @@ In this part of the exercise, you will create another Temporal client that sends
2. Within the `main()` block, add the `client.QueryWorkflow()` function with the necessary parameters and error handling:

```go
response, err := c.QueryWorkflow(context.Background(), "queries", "", "current_state")
response, err := c.QueryWorkflow(context.Background(), "queries-workflow-id", "", "current_state")
Comment on lines -44 to +49
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not necessary, but it had the workflow id and the task queue both as "queries", so I just changed them to disambiguate

if err != nil {
log.Fatalln("Error sending the Query", err)
return
Expand All @@ -67,8 +72,8 @@ At this point, you can run your Workflow. Because it is the same Workflow from t

```
2024/03/14 08:48:10 INFO No logger configured for temporal client. Created default one.
2024/03/14 08:48:10 INFO Started Worker Namespace default TaskQueue queries WorkerID 43388@Omelas@
2024/03/14 08:48:21 INFO Query workflow started Namespace default TaskQueue queries WorkerID 43388@Omelas@ WorkflowType Workflow WorkflowID queries RunID 905330da-9c0f-490e-bd48-c6a9e8840f7a Attempt 1 input Plain text input
2024/03/14 08:48:10 INFO Started Worker Namespace default TaskQueue queries-task-queue WorkerID 43388@Omelas@
2024/03/14 08:48:21 INFO Query workflow started Namespace default TaskQueue queries-task-queue WorkerID 43388@Omelas@ WorkflowType Workflow WorkflowID queries-workflow-id RunID 905330da-9c0f-490e-bd48-c6a9e8840f7a Attempt 1 input Plain text input
```

1. You can now Query your Workflow. In a third terminal, run `go run queryclient/main.go`. It will send a Query to your Workflow, which will immediately return the Query result:
Expand All @@ -85,7 +90,7 @@ To send a Query from the CLI, use `temporal workflow query` with the same parame

```bash
temporal workflow query \
--workflow-id="queries" \
--workflow-id="queries-workflow-id" \
--type="current_state"
```

Expand All @@ -96,15 +101,20 @@ Query result:
["waiting for signal"]
```

Now you can send a Signal to your Workflow as in the previous exercise so it completes successfully. In the terminal you sent your Query from, run `go run signalclient/main.go`.
Now you can send a Signal to your Workflow as in the previous exercise so it completes successfully.

1. In the terminal you sent your Query from, run `go run signalclient/main.go`.
Comment on lines -99 to +106
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

separating prose from instructions. up to you 👍


## Part E: Querying a Completed Workflow

Finally, you can demonstrate querying completed Workflows. Update the `currentState` variable in `workflow.go` once more just before the Workflow returns, so that you can demonstrate querying a completed workflow. Then, re-run the workflow, and query it from the command line again:
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved to part A

Now that the Workflow has been signalled, it has completed, and you
can demonstrate querying completed Workflows.

1. Query it from the command line again:

```bash
temporal workflow query \
--workflow-id="queries" \
--workflow-id="queries-workflow-id" \
--type="current_state"
```

Expand Down
4 changes: 2 additions & 2 deletions exercises/querying-workflows/practice/signalclient/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"context"
"log"

queries "interacting/exercises/querying-workflows/solution"
queries "interacting/exercises/querying-workflows/practice"
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

significant change -- the practice code was importing from the solution, so the user's code would be working even if they didn't solve the problem yet. Lol I had this happen to me and i was pretty confused


"go.temporal.io/sdk/client"
)
Expand All @@ -20,7 +20,7 @@ func main() {
Fulfilled: true,
}

err = c.SignalWorkflow(context.Background(), "queries", "", "fulfill-order-signal", signal)
err = c.SignalWorkflow(context.Background(), "queries-workflow-id", "", "fulfill-order-signal", signal)
if err != nil {
log.Fatalln("Error sending the Signal", err)
return
Expand Down
6 changes: 3 additions & 3 deletions exercises/querying-workflows/practice/starter/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"context"
"log"

queries "interacting/exercises/querying-workflows/solution"
queries "interacting/exercises/querying-workflows/practice"

"go.temporal.io/sdk/client"
)
Expand All @@ -17,8 +17,8 @@ func main() {
defer c.Close()

workflowOptions := client.StartWorkflowOptions{
ID: "queries",
TaskQueue: "queries",
ID: "queries-workflow-id",
TaskQueue: "queries-task-queue",
}

we, err := c.ExecuteWorkflow(
Expand Down
4 changes: 2 additions & 2 deletions exercises/querying-workflows/practice/worker/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package main
import (
"log"

queries "interacting/exercises/querying-workflows/solution"
queries "interacting/exercises/querying-workflows/practice"

"go.temporal.io/sdk/client"
"go.temporal.io/sdk/worker"
Expand All @@ -16,7 +16,7 @@ func main() {
}
defer c.Close()

w := worker.New(c, "queries", worker.Options{})
w := worker.New(c, "queries-task-queue", worker.Options{})

w.RegisterWorkflow(queries.Workflow)
w.RegisterActivity(queries.Activity)
Expand Down
2 changes: 1 addition & 1 deletion exercises/querying-workflows/practice/workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func Workflow(ctx workflow.Context, input string) (string, error) {
logger.Error("Activity failed.", "Error", err)
return "", err
}
// TODO Part E: Update the `currentState` variable after the Workflow has
// TODO Part A: Update the `currentState` variable after the Workflow has
// has completed, so that you can query it later.
logger.Info("Signal workflow completed.", "result", result)
}
Expand Down
2 changes: 1 addition & 1 deletion exercises/querying-workflows/solution/queryclient/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ func main() {
}
defer c.Close()

response, err := c.QueryWorkflow(context.Background(), "queries", "", "current_state")
response, err := c.QueryWorkflow(context.Background(), "queries-workflow-id", "", "current_state")
if err != nil {
log.Fatalln("Error sending the Query", err)
return
Expand Down
2 changes: 1 addition & 1 deletion exercises/querying-workflows/solution/signalclient/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func main() {
Fulfilled: true,
}

err = c.SignalWorkflow(context.Background(), "queries", "", "fulfill-order-signal", signal)
err = c.SignalWorkflow(context.Background(), "queries-workflow-id", "", "fulfill-order-signal", signal)
if err != nil {
log.Fatalln("Error sending the Signal", err)
return
Expand Down
4 changes: 2 additions & 2 deletions exercises/querying-workflows/solution/starter/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ func main() {
defer c.Close()

workflowOptions := client.StartWorkflowOptions{
ID: "queries",
TaskQueue: "queries",
ID: "queries-workflow-id",
TaskQueue: "queries-task-queue",
}

we, err := c.ExecuteWorkflow(
Expand Down
2 changes: 1 addition & 1 deletion exercises/querying-workflows/solution/worker/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func main() {
}
defer c.Close()

w := worker.New(c, "queries", worker.Options{})
w := worker.New(c, "queries-task-queue", worker.Options{})

w.RegisterWorkflow(queries.Workflow)
w.RegisterActivity(queries.Activity)
Expand Down
4 changes: 2 additions & 2 deletions exercises/sending-signals-client/practice/workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ func Workflow(ctx workflow.Context, input string) (string, error) {
signalChan := workflow.GetSignalChannel(ctx, "fulfill-order-signal")
signalChan.Receive(ctx, &signal)
// TODO Part B: Wrap the `ExecuteActivity()`` call and the `logger.Info()` call
// in a test for `if signal.Fulfilled == true`. This will block the Workflow
// until a Signal is received on the `signalChan` defined above.
// in a test for `if signal.Fulfilled == true`.
// This won't run until a Signal is received because `signalChan.Receive` above blocks.
err := workflow.ExecuteActivity(ctx, Activity, input).Get(ctx, &result)
if err != nil {
logger.Error("Activity failed.", "Error", err)
Expand Down
71 changes: 42 additions & 29 deletions exercises/sending-signals-external/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,53 +14,66 @@ the complete version in the `solution` subdirectory.

## Part A: Defining a Signal

1. This exercise contains one Client that runs two different Workflows
— `PizzaWorkflow` and `FulfillOrderWorkflow`. Both Workflows are defined in
`workflow.go`. `PizzaWorkflow` is designed not to complete its final activity
— `SendBill` — until it receives a Signal from `FulfillOrderWorkflow`. You'll
start by defining that Signal. Edit `workflow.go`. Near the top of the file,
This exercise contains one Client that runs two different Workflows
— `PizzaWorkflow` and `FulfillOrderWorkflow`. Both Workflows are defined in
`workflow.go`. `PizzaWorkflow` is designed not to complete its final activity
— `SendBill` — until it receives a Signal from `FulfillOrderWorkflow`. You'll
start by defining that Signal.

1. Edit `workflow.go`. Near the top of the file,
Comment on lines -17 to +23
Copy link
Author

@GSmithApps GSmithApps Jan 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prose from instruction

after the `import()` block and before your Workflow definitions, create a
type of `struct{}` named `FulfillOrderSignal` that contains a single `bool`
named `Fulfilled`.
2. Next, directly below that, create a `var` named `signal` that is an instance
of `FulfillOrderSignal` with `Fulfilled: true`. This is the Signal that
`FulfillOrderWorkflow` will send to `PizzaWorkflow`.
3. Save the file.
2. Save the file.

## Part B: Handling the Signal

1. Next, you need to enable your `PizzaWorkflow` to receive a Signal from
`FulfillOrderWorkflow`. After `var confirmation OrderConfirmation`, define a
Signal Channel, and use `signalChan.Receive()` to block the Workflow until it
receives a Signal, after which it can proceed with the logic contained in `if
signal.Fulfilled == true{}`. Begin by adding a call to
`workflow.GetSignalChannel(ctx, "fulfill-order-signal")` and assign it to
a variable like `signalChan`.
2. After that, add `signalChan.Receive(ctx, &signal)` on the following line.
3. Save the file.
Next, you need to enable your `PizzaWorkflow` to receive a Signal from
`FulfillOrderWorkflow`.

After `var confirmation OrderConfirmation`, define a
Signal Channel, and use `signalChan.Receive()` to block the Workflow until it
receives a Signal, after which it can proceed with the logic contained in
`if receivedSignal.Fulfilled == true{}`.

1. Create a `var` named `receivedSignal` that is an instance
of `FulfillOrderSignal`. This is the Signal that
`PizzaWorkflow` will receive from `FulfillOrderWorkflow`.
2. Add `signalChan := workflow.GetSignalChannel(ctx, "fulfill-order-signal")`.
3. On the following line, add `signalChan.Receive(ctx, &receivedSignal)`.
4. Save the file.

## Part C: Signaling your Workflow

1. Near the bottom of `workflow.go`, within `FulfillOrderWorkflow`, you will
notice that it runs two Activities — `MakePizzas` and `DeliverPizzas`. After
those Activities complete successfuly, the next step should be to send a
Signal to the `PizzaWorkflow` that it is time to bill the customer and
complete the Workflow. To do this, you need call
`workflow.SignalExternalWorkflow()`.
2. Add this call to the end of `FulfillOrderWorkflow`. `SignalExternalWorkflow`
needs, as arguments, the `ctx` Workflow context, Workflow ID (which should be
Near the bottom of `workflow.go`, within `FulfillOrderWorkflow`, you will
notice that it runs two Activities — `MakePizzas` and `DeliverPizzas`. After
those Activities complete successfuly, the next step should be to send a
Signal to the `PizzaWorkflow` that it is time to bill the customer and
complete the Workflow. To do this, you need call
`workflow.SignalExternalWorkflow()`.

1. Create a `var` named `signalToSend` that is an instance
of `FulfillOrderSignal` with `Fulfilled: true`. This is the Signal that
`FulfillOrderWorkflow` will send to `PizzaWorkflow`.
2. Add a call to `workflow.SignalExternalWorkflow()` at the end of `FulfillOrderWorkflow`. `SignalExternalWorkflow`
needs the following as arguments: the `ctx` Workflow context, Workflow ID (which should be
`pizza-workflow-order-Z1238`), an optional Run ID (which you can omit by
providing "" as the next argument), and the name of the
providing "" as the argument), and the name of the
Signal,`fulfill-order-signal`. For `SignalExternalWorkflow` calls to block
and return properly in Go, you also need to append `.Get(ctx,
[return-value-pointer])` to a `SignalExternalWorkflow` call, though
`[return-value-pointer]` can be `nil` here.
@@@@@ the course content doesn't say anything about this `.Get`. @@@@
Copy link
Author

@GSmithApps GSmithApps Jan 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't see this in the course content. I'm not sure I know what's going on here, but maybe that's okay and if this is good, then we can just keep it

related to these two: a and b

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, is this just about appending .Get() to a call so it actually blocks and returns? That's definitely worth clarifying in the course content if so.

3. Save and close the file.

## Part D: Making your Client start both Workflows

1. Finally, open `start/main.go` for editing. Currently, this Client only starts
the `PizzaWorkflow`. Directly after the `c.ExecuteWorkflow()` call for the
1. Finally, open `start/main.go` for editing.

Currently, this Client only starts
the `PizzaWorkflow`.

2. Directly after the `c.ExecuteWorkflow()` call for the
`PizzaWorkflow`, add another call that starts the `FulfillOrderWorkflow`. You
can use the call that starts the `PizzaWorkflow` and the
`signalFulfilledOptions` block as a reference. Don't forget to capture the
Expand Down
11 changes: 6 additions & 5 deletions exercises/sending-signals-external/practice/workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ import (
// TODO Part A: Create a type of `struct{}` named `FulfillOrderSignal`
// that contains a single `bool` named `Fulfilled`.

// TODO Part A: create a `var` named `signal` that is an instance of
// `FulfillOrderSignal` with `Fulfilled: true`. This is the Signal that
// `FulfillOrderWorkflow` will send to `PizzaWorkflow`.
Comment on lines -14 to -16
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we were using the signal variable as both the sending variable and the receiving variable, which I felt a little confused by. So I just made two variables -- a sent one and a received one -- both of which are in just function scopes instead of at the top


func PizzaWorkflow(ctx workflow.Context, order PizzaOrder) (OrderConfirmation, error) {
retrypolicy := &temporal.RetryPolicy{
Expand Down Expand Up @@ -48,9 +45,9 @@ func PizzaWorkflow(ctx workflow.Context, order PizzaOrder) (OrderConfirmation, e
var confirmation OrderConfirmation
// TODO Part B: Add a call to `workflow.GetSignalChannel(ctx, "fulfill-order-signal")`
// and assign it to a variable like `signalChan`. After that, add
// `signalChan.Receive(ctx, &signal)` on the following line.
// `signalChan.Receive(ctx, &receivedSignal)` on the following line.

if signal.Fulfilled == true {
if receivedSignal.Fulfilled == true {
bill := Bill{
CustomerID: order.Customer.CustomerID,
OrderNumber: order.OrderNumber,
Expand Down Expand Up @@ -94,6 +91,10 @@ func FulfillOrderWorkflow(ctx workflow.Context, order PizzaOrder) (string, error
return "orderUnfulfilled", nil
}

// TODO Part C: create a `var` named `signalToSend` that is an instance of
// `FulfillOrderSignal` with `Fulfilled: true`. This is the Signal that
// `FulfillOrderWorkflow` will send to `PizzaWorkflow`.

// TODO Part C: call `workflow.SignalExternalWorkflow()`
// to send a Signal to your `PizzaWorkflow`.

Expand Down
Loading