Skip to main content

Awakeables

Awakeables pause an invocation while waiting for another process to complete a task. You can use this pattern to let a handler execute a task somewhere else and retrieve the result. This pattern is also known as the callback (task token) pattern.

Creating awakeables

  1. The handler creates an awakeable. This contains a String identifier and a handle on the future result.

awakeable := restate.Awakeable[string](ctx)
awakeableId := awakeable.Id()
if _, err := restate.Run(ctx, func(ctx restate.RunContext) (string, error) {
return triggerTaskAndDeliverId(awakeableId)
}); err != nil {
return err
}
payload, err := awakeable.Result()
if err != nil {
return err
}

  1. The handler triggers a task/process and attaches the awakeable ID (e.g. over Kafka, via HTTP,...). For example, send an HTTP request to a service that executes the task, and attach the ID to the payload. You use restate.Run to avoid re-triggering the task on retries.

awakeable := restate.Awakeable[string](ctx)
awakeableId := awakeable.Id()
if _, err := restate.Run(ctx, func(ctx restate.RunContext) (string, error) {
return triggerTaskAndDeliverId(awakeableId)
}); err != nil {
return err
}
payload, err := awakeable.Result()
if err != nil {
return err
}

  1. The handler waits until the other process has executed the task. The handler receives the payload and resumes.

awakeable := restate.Awakeable[string](ctx)
awakeableId := awakeable.Id()
if _, err := restate.Run(ctx, func(ctx restate.RunContext) (string, error) {
return triggerTaskAndDeliverId(awakeableId)
}); err != nil {
return err
}
payload, err := awakeable.Result()
if err != nil {
return err
}

  1. The handler creates an awakeable. This contains a String identifier and a handle on the future result.
  1. The handler triggers a task/process and attaches the awakeable ID (e.g. over Kafka, via HTTP,...). For example, send an HTTP request to a service that executes the task, and attach the ID to the payload. You use restate.Run to avoid re-triggering the task on retries.
  1. The handler waits until the other process has executed the task. The handler receives the payload and resumes.

awakeable := restate.Awakeable[string](ctx)
awakeableId := awakeable.Id()
if _, err := restate.Run(ctx, func(ctx restate.RunContext) (string, error) {
return triggerTaskAndDeliverId(awakeableId)
}); err != nil {
return err
}
payload, err := awakeable.Result()
if err != nil {
return err
}

Completing awakeables

The external process completes the awakeable by either resolving it with an optional payload or by rejecting it with its ID and a reason for the failure. This throws a terminal error in the waiting handler.

  • Resolving over HTTP with its ID and an optional payload:

curl localhost:8080/restate/awakeables/prom_1PePOqp/resolve
-H 'content-type: application/json'
-d '{"hello": "world"}'

  • Resolving over HTTP with its ID and an optional payload:

curl localhost:8080/restate/awakeables/prom_1PePOqp/resolve
-H 'content-type: application/json'
-d '{"hello": "world"}'

  • Rejecting over HTTP with its ID and a reason:

curl localhost:8080/restate/awakeables/prom_1PePOqp/reject
-H 'content-type: text/plain' \
-d 'Very bad error!'

  • Rejecting over HTTP with its ID and a reason:

curl localhost:8080/restate/awakeables/prom_1PePOqp/reject
-H 'content-type: text/plain' \
-d 'Very bad error!'

  • Resolving via the SDK with its ID and an optional payload:

restate.ResolveAwakeable(ctx, awakeableId, "hello")

  • Resolving via the SDK with its ID and an optional payload:

restate.ResolveAwakeable(ctx, awakeableId, "hello")

  • Rejecting via the SDK with its ID and a reason:

restate.RejectAwakeable(ctx, awakeableId, fmt.Errorf("my error reason"))

  • Rejecting via the SDK with its ID and a reason:

restate.RejectAwakeable(ctx, awakeableId, fmt.Errorf("my error reason"))

Result serialization

You can resolve an awakeable with any payload that can be serialized. By default, serialization is done with JSONCodec which uses encoding/json. If you don't need to provide anything, you can use restate.Void{} which serializes to a nil byte slice.

Cost savings on FaaS

When running on Function-as-a-Service platforms, such as AWS Lambda, Restate suspends the handler while waiting for the awakeable to be completed. Since you only pay for the time that the handler is actually running, your don't pay while waiting for the external process to return.

Awaiting awakeables in Virtual Objects

Virtual Objects only process a single invocation at a time, so the Virtual Object will be blocked while waiting on the awakeable to be resolved.