Skip to content

Commit 843de52

Browse files
committed
Update basics go
1 parent f0ef9f8 commit 843de52

File tree

9 files changed

+105
-7
lines changed

9 files changed

+105
-7
lines changed

go/basics/README.md

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,34 @@ about how they work and how they can be run.
99

1010
### Examples
1111

12-
* **[Durable Execution](src/1_durable_execution.ts):** Running code cleanly
12+
* **[Durable Execution](part0/durableexecution.go):** Running code cleanly
1313
to the end in the presence of failures. Automatic retries and recovery of previously
1414
finished actions. The example applies creates a subscription to movie streaming services
1515
by first creating a recurring payment and then adding the subscriptions.
1616

17-
* **[Workflows](src/2_workflows.ts):** Workflows are durable execution tasks that can
17+
* **[Building blocks](part1/buildingblocks.go):** Restate gives you a durable version
18+
of common building blocks like queues, promises, RPC, state, and timers.
19+
This example shows a handler which processes payment failure events from a payment provider.
20+
The handler reminds the customer for 3 days to update their payment details, and otherwise cancels the subscriptions.
21+
22+
* **[Virtual Objects](part2/virtualobjects.go):** Stateful serverless objects
23+
to manage durable consistent state and state-manipulating logic.
24+
25+
* **[Workflows](part3/workflows.go):** Workflows are durable execution tasks that can
1826
be submitted and awaited. They have an identity and can be signaled and queried
1927
through durable promises. The example is a user-signup flow that takes multiple
2028
operations, including verifying the email address.
2129

22-
* **[Virtual Objects](src/3_virtual_objects.ts):** Stateful serverless objects
23-
to manage durable consistent state and state-manipulating logic.
24-
2530
### Running the examples
2631

2732
1. [Start the Restate Server](https://docs.restate.dev/develop/local_dev) in a separate shell:
2833
`restate-server`
2934

3035
2. Start the relevant example:
3136
- `go run ./part1` for the Durable Execution example
32-
- `go run ./part2` for the Workflows example
33-
- `go run ./part3` for the Virtual Objects example
37+
- The building blocks example is not runnable and more like a reference of what you can do with the API
38+
- `go run ./part2` for the Virtual Objects example
39+
- `go run ./part3` for the Workflows example
3440

3541
3. Register the example at Restate server by calling
3642
`restate -y deployment register --force "localhost:9080"`.
File renamed without changes.

go/basics/part1/buildingblocks.go

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package main
2+
3+
import (
4+
restate "github.com/restatedev/sdk-go"
5+
"log/slog"
6+
"time"
7+
)
8+
9+
type SubscriptionRequest struct {
10+
UserID string `json:"userId"`
11+
}
12+
13+
type MyService struct{}
14+
15+
func (MyService) Run(ctx restate.Context) error {
16+
// 1. IDEMPOTENCY: Add an idempotency key to the header of your requests
17+
// Restate deduplicates calls automatically. Nothing to do here.
18+
19+
// 2. DURABLE RPC: Call other services without manual retry and deduplication logic
20+
// Restate persists all requests and ensures execution till completion
21+
response, err := restate.Object[string](ctx, "SubscriptionService", "my-sub-123", "Add").
22+
Request(SubscriptionRequest{UserID: "123"})
23+
if err != nil {
24+
return err
25+
}
26+
slog.Info("Response was: " + response)
27+
28+
// 3. DURABLE MESSAGING: send (delayed) messages to other services without deploying a message broker
29+
// Restate persists the timers and triggers execution
30+
restate.ObjectSend(ctx, "SubscriptionService", "my-sub-123", "Add").
31+
Send(SubscriptionRequest{UserID: "123"})
32+
33+
// 4. DURABLE PROMISES: tracked by Restate, can be moved between processes and survive failures
34+
// Awakeables: block the workflow until notified by another handler
35+
awakeable := restate.Awakeable[string](ctx)
36+
// Wait on the result
37+
result, err := awakeable.Result()
38+
if err != nil {
39+
return err
40+
}
41+
slog.Info("Promise resolved", "result", result)
42+
// Another process can resolve an awakeable with its ID
43+
restate.ResolveAwakeable[string](ctx, awakeable.Id(), "hello")
44+
45+
// 5. DURABLE TIMERS: sleep or wait for a timeout, tracked by Restate and recoverable
46+
// When this runs on FaaS, the handler suspends and the timer is tracked by Restate
47+
// Example of durable recoverable sleep
48+
// If the service crashes two seconds later, Restate will invoke it after another 3 seconds
49+
err = restate.Sleep(ctx, 5*time.Second)
50+
if err != nil {
51+
return err
52+
}
53+
// Example of waiting on a promise (awakeable/call/...) or a timeout
54+
timeout := restate.After(ctx, 5*time.Second)
55+
selector := restate.Select(ctx, awakeable, timeout)
56+
switch selector.Select() {
57+
case awakeable:
58+
result, err := awakeable.Result()
59+
if err != nil {
60+
return err
61+
}
62+
slog.Info("Awakeable won with result: " + result)
63+
case timeout:
64+
if err := timeout.Done(); err != nil {
65+
return err
66+
}
67+
slog.Info("Sleep won")
68+
}
69+
// Example of scheduling a handler for later on
70+
restate.ObjectSend(ctx, "SubscriptionService", "my-sub-123", "Cancel").
71+
Send(nil, restate.WithDelay(24*time.Hour))
72+
73+
// 7. PERSIST RESULTS: avoid re-execution of actions on retries
74+
// Use this for non-deterministic actions or interaction with APIs, DBs, ...
75+
// For example, generate idempotency keys that are stable across retries
76+
// Then use these to call other APIs and let them deduplicate
77+
paymentDeduplicationID := restate.Rand(ctx).UUID().String()
78+
success, err := restate.Run(ctx, func(ctx restate.RunContext) (string, error) {
79+
return chargeBankAccount(paymentDeduplicationID, 100)
80+
})
81+
if err != nil {
82+
return err
83+
}
84+
slog.Info("Payment was successful: " + success)
85+
86+
return nil
87+
}
88+
89+
func chargeBankAccount(paymentDeduplicationID string, amount int64) (string, error) {
90+
// Implementation here
91+
return "", nil
92+
}
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)