Skip to content

Commit

Permalink
Remove references to line numbers in TypeScript SDK docs
Browse files Browse the repository at this point in the history
  • Loading branch information
gvdongen committed Jun 21, 2024
1 parent b8807f2 commit 1fe5999
Show file tree
Hide file tree
Showing 13 changed files with 136 additions and 131 deletions.
10 changes: 8 additions & 2 deletions code_snippets/ts/src/develop/awakeable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,20 @@ const service = restate.service({
name: "Awakeable",
handlers: {
greet: async (ctx: restate.Context, name: string) => {
// <start_create>
// <start_here>
// <mark_1>
const awakeable = ctx.awakeable<string>();
const awakeableId = awakeable.id
// </mark_1>

// <mark_2>
await ctx.run(() => triggerTaskAndDeliverId(awakeableId));
// </mark_2>

// <mark_3>
const payload = await awakeable.promise;
// <end_create>
// </mark_3>
// <end_here>

// <start_resolve>
ctx.resolveAwakeable(awakeableId, "hello");
Expand Down
5 changes: 4 additions & 1 deletion code_snippets/ts/src/develop/my_service.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import * as restate from "@restatedev/restate-sdk";
import {Context} from "@restatedev/restate-sdk";

const myService = restate.service({
name: "MyService",
handlers: {
myHandler: async (ctx: restate.Context, greeting: string) => {
myHandler: async (ctx: Context, greeting: string) => {
return `${greeting}!`;
},
}
})

// <start_api_export>
export const MyService: typeof myService = { name: "MyService" };
// <end_api_export>

restate
.endpoint()
Expand Down
12 changes: 7 additions & 5 deletions code_snippets/ts/src/develop/my_virtual_object.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import * as restate from "@restatedev/restate-sdk";
import {handlers} from "@restatedev/restate-sdk";
import {handlers, ObjectContext, ObjectSharedContext} from "@restatedev/restate-sdk";

const myVirtualObject = restate.object({
name: "MyVirtualObject",
handlers: {
myHandler: async (ctx: restate.ObjectContext, greeting: string) => {
myHandler: async (ctx: ObjectContext, greeting: string) => {
return `${greeting} ${ctx.key}!`;
},
myConcurrentHandler: handlers.object.shared(async (ctx: restate.ObjectSharedContext, greeting: string) => {
return `${greeting} ${ctx.key}!`;
}),
myConcurrentHandler: handlers.object.shared(
async (ctx: ObjectSharedContext, greeting: string) => {
return `${greeting} ${ctx.key}!`;
}
),
}
})

Expand Down
4 changes: 2 additions & 2 deletions code_snippets/ts/src/develop/service_communication.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ const service = restate.service({
// <end_delayed_object>

// <start_ordering>
ctx.objectSendClient(MyVirtualObject, "Mary").myHandler("Hi!");
ctx.objectSendClient(MyVirtualObject, "Mary").myHandler("Hi again!");
ctx.objectSendClient(MyVirtualObject, "Mary").myHandler("I'm call A");
ctx.objectSendClient(MyVirtualObject, "Mary").myHandler("I'm call B");
// <end_ordering>
},
callWorkflows: async (ctx: restate.Context, name: string) => {
Expand Down
5 changes: 3 additions & 2 deletions code_snippets/ts/src/develop/workflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,19 @@

// <start_here>
import * as restate from "@restatedev/restate-sdk";
import {WorkflowContext, WorkflowSharedContext} from "@restatedev/restate-sdk";

const myWorkflow = restate.workflow({
name: "MyWorkflow",
handlers: {
run: async (ctx: restate.WorkflowContext, req: string) => {
run: async (ctx: WorkflowContext, req: string) => {

// implement workflow logic here

return "success";
},

interactWithWorkflow: async (ctx: restate.WorkflowSharedContext) => {
interactWithWorkflow: async (ctx: WorkflowSharedContext) => {
// implement interaction logic here
},
},
Expand Down
5 changes: 3 additions & 2 deletions docs/develop/java/awakeables.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ This pattern is also known as the callback (task token) pattern.

2. 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 `ctx.run` to avoid retriggering the task this on retries.
You use `ctx.run` to avoid re-triggering the task on retries.

```java
CODE_LOAD::java/src/main/java/develop/Awakeables.java?2
Expand Down Expand Up @@ -59,7 +59,7 @@ This pattern is also known as the callback (task token) pattern.

2. 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 `ctx.runBlock` to avoid retriggering the task this on retries.
You use `ctx.runBlock` to avoid re-triggering the task on retries.

```kotlin
CODE_LOAD::kotlin/src/main/kotlin/develop/Awakeables.kt?2
Expand All @@ -77,6 +77,7 @@ This pattern is also known as the callback (task token) pattern.
</CH.Scrollycoding>
</TabItem>
</Tabs>

## Completing awakeables

The external process completes the awakeable by either resolving it with an optional payload or by rejecting it
Expand Down
111 changes: 67 additions & 44 deletions docs/develop/ts/awakeables.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,51 +12,74 @@ Awakeables pause an invocation while waiting for another process to complete a t
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.

<CH.Section>
<CH.Code>
```typescript my_handler.ts
CODE_LOAD::ts/src/develop/awakeable.ts#create
```
</CH.Code>

1. [The handler **creates an awakeable**](focus://1,2). This contains a [String identifier](focus://2) and a Promise/Awaitable.
2. [The handler **triggers a task/process** and attaches the awakeable ID](focus://4) (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 `ctx.run` to avoid retriggering the task this on retries.
3. [The handler **waits** until the other process has executed the task.](focus://6)
</CH.Section>
<CH.Section>
4. **The external process completes the awakeable** when the task is finished by:

<CH.Code>
```shell resolve_curl.sh
curl localhost:8080/restate/awakeables/prom_1PePOqp/resolve -H 'content-type: application/json'
-d '{"hello": "world"}'
```

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

```typescript external_process_resolve.ts
CODE_LOAD::ts/src/develop/awakeable.ts#resolve
```

```typescript external_proces_reject.ts
CODE_LOAD::ts/src/develop/awakeable.ts#reject
```

</CH.Code>
- **Resolving** the awakeable
- [Over HTTP](focus://resolve_curl.sh#1:2) with [its ID](focus://resolve_curl.sh#1[40:52]) and [an optional payload](focus://resolve_curl.sh#2)
- [Via the SDK with its ID and an optional payload](focus://external_process_resolve.ts#1)
- **Rejecting** the awakeable. This throws [a terminal error](/develop/java/error-handling) in the waiting handler.
- [Over HTTP](focus://reject_curl.sh#1:2) with [its ID](focus://reject_curl.sh#1[40:52]) and [a failure reason](focus://reject_curl.sh#2)
- [Via the SDK with its ID and a failure reason](focus://external_proces_reject.ts#1)
</CH.Section>
5. The handler **receives the payload and resumes**.
## Creating awakeables

<CH.Scrollycoding className={"spotlight-medium"}>

1. The handler **creates an awakeable**. This contains a String identifier and a Promise.

```ts
CODE_LOAD::ts/src/develop/awakeable.ts?1
```
---
2. 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 `ctx.run` to avoid re-triggering the task on retries.
```ts
CODE_LOAD::ts/src/develop/awakeable.ts?2
```
---
3. The handler **waits** until the other process has executed the task.
The handler **receives the payload and resumes**.
```ts
CODE_LOAD::ts/src/develop/awakeable.ts?3
```
</CH.Scrollycoding>
## 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](/develop/java/error-handling) in the waiting handler.
<CH.Scrollycoding className={"single-item spotlight-medium"}>
- Resolving over HTTP with its ID and an optional payload:
```shell
curl localhost:8080/restate/awakeables/prom_1PePOqp/resolve
-H 'content-type: application/json'
-d '{"hello": "world"}'
```
</CH.Scrollycoding>
<CH.Scrollycoding className={"single-item spotlight-medium"}>
- Rejecting over HTTP with its ID and a reason:

```shell
curl localhost:8080/restate/awakeables/prom_1PePOqp/reject
-H 'content-type: text/plain' \
-d 'Very bad error!'
```
</CH.Scrollycoding>
<CH.Scrollycoding className={"single-item spotlight-medium"}>
- Resolving via the SDK with its ID and an optional payload:

```ts
CODE_LOAD::ts/src/develop/awakeable.ts#resolve
```
</CH.Scrollycoding>
<CH.Scrollycoding className={"single-item spotlight-medium"}>
- Rejecting via the SDK with its ID and a reason:

```ts
CODE_LOAD::ts/src/develop/awakeable.ts#reject
```
</CH.Scrollycoding>


<Admonition type="info" title={"Payload serialization"}>
Expand Down
56 changes: 20 additions & 36 deletions docs/develop/ts/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -21,69 +21,53 @@ Handlers can either be part of a [Service](/concepts/services#services-1), a [Vi
## Services

[Services](/concepts/services#services-1) and their handlers are defined as follows:
<CH.Section>
<CH.Code>

```typescript
CODE_LOAD::ts/src/develop/my_service.ts
```

</CH.Code>

- [Create the service](focus://3,10)
- Specify [the service name.](focus://4) The service can then be called at `<RESTATE_INGRESS_URL>/MyService/myHandler`.
- [List the handlers.](focus://5:8)
[Each handler has a name (`myHandler`) and a function that implements the handler logic.](focus://6)
- Specify that you want to create a Service via _`restate.service`_.
- Specify the service name. The service can then be called at `<RESTATE_INGRESS_URL>/MyService/myHandler`.
- The service definition contains a list of handlers.
Each handler has a name (`myHandler`) and a function that implements the handler logic.
The function has the Restate Context as its first argument.
Within the handler, you use the `Context` to interact with Restate.
The SDK stores the actions you do on the context in the Restate journal to make them durable.
- The handler input parameters and return type are optional and can be of any type, as long as they can be serialized as a Buffer with _`Buffer.from(JSON.stringify(yourObject))`_ and deserialized with _`JSON.parse(result.toString()) as T`_.
- [Export the service definition](focus://12) so that it can be used by other handlers to call the service. (See [Service Communication docs](/develop/ts/service-communication).)
- [Create an endpoint](focus://14,15) and [bind the service(s)](focus://16) to the Restate endpoint. [Listen](focus://17) on the specified port (default `9080`) for connections and requests.

</CH.Section>
- Export the service definition `MyService` so that it can be used by other handlers to call the service. (See [Service Communication docs](/develop/ts/service-communication).)
- Finally, create an endpoint and bind the service(s) to the Restate endpoint. Listen on the specified port (default `9080`) for connections and requests.

## Virtual Objects

[Virtual Objects](/concepts/services#virtual-objects) and their handlers are defined similarly to services, with the following differences:

<CH.Section>
<CH.Code>

```typescript
CODE_LOAD::ts/src/develop/my_virtual_object.ts
```

</CH.Code>

- [Create the virtual object](focus://4)
- [The first argument of the handler must be the `ObjectContext` parameter](focus://7).
- Specify that you want to create a Virtual Object via _`restate.object`_.
- The first argument of each handler must be the `ObjectContext` parameter.
Handlers with the `ObjectContext` parameter can write to the K/V state store.
Only one handler can be active at a time, to ensure consistency.
- [If you want to have a handler that executes concurrently to the others and doesn't have write access to the K/V state, wrap the handler in `handlers.object.shared` and use the `ObjectSharedContext`.](focus://10)
- If you want to have a handler that executes concurrently to the others and doesn't have write access to the K/V state, wrap the handler in `handlers.object.shared` and use the `ObjectSharedContext`.
For example, you can use these handlers to read K/V state, or interact with the blocking handler.
</CH.Section>

## Workflows

[Workflows](/concepts/services#workflows) are a special type of Virtual Objects, their definition is similar but with the following differences:

<CH.Section>
<CH.Code lineNumbers={"true"}>

```typescript
CODE_LOAD::ts/src/develop/workflow.ts
```

</CH.Code>

- [Create the workflow](focus://3,17)
- [Every workflow implementation needs to have a handler called `run` that implements the workflow logic. This handler uses the `WorkflowContext` to interact with the SDK. The `run` handler executes exactly one time per workflow execution/object.](focus://6:11)
- [The other handlers of the workflow are used to interact with the workflow: either query it, or signal it. They use the `WorkflowSharedContext` to interact with the SDK. These handlers can run concurrently with the `run` handler and can still be called after the `run` handler has finished.](focus://13:15)
- [Have a look at the workflow docs to learn more.](/develop/ts/workflows)

</CH.Section>
```typescript
CODE_LOAD::ts/src/develop/workflow.ts
```

- Create the workflow with _`restate.workflow`_.
- Every workflow implementation needs to have a handler called `run` that implements the workflow logic.
This handler uses the `WorkflowContext` to interact with the SDK.
The `run` handler executes exactly one time per workflow execution/object.
- The other handlers of the workflow are used to interact with the workflow: either query it, or signal it.
They use the `WorkflowSharedContext` to interact with the SDK.
These handlers can run concurrently with the `run` handler and can still be called after the `run` handler has finished.
- [Have a look at the workflow docs to learn more.](/develop/ts/workflows)


Now that you have a high-level idea of what a Restate service might look like, let's have a look at what the Restate Context allows you to do.
25 changes: 8 additions & 17 deletions docs/develop/ts/service-communication.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,9 @@ A handler can call another handler and wait for the response (request-response),
<Admonition type="note" title="Exporting the service definition">
Make sure you export the service definition of the service you want to call, as we did in the [service example on the overview page](/develop/ts/overview#services):

<CH.Code lineNumbers={"true"} rows={"focus"} >

```typescript focus=12
CODE_LOAD::ts/src/develop/my_service.ts
```
</CH.Code>

```typescript
CODE_LOAD::ts/src/develop/my_service.ts#api_export
```
Import this service definition in the service handler that wants to call it.
</Admonition>

Expand Down Expand Up @@ -149,19 +145,14 @@ To schedule a delayed call, send a message with a delay parameter, as follows:
</Admonition>

<Admonition type="note" title="Ordering guarantees in Virtual Objects">
<CH.Section>
Invocations to a Virtual Object are executed serially.
Invocations will execute in the same order in which they arrive at Restate.
For example, assume a handler calls the same Virtual Object twice:

<CH.Code lineNumbers={"true"}>
```typescript
CODE_LOAD::ts/src/develop/service_communication.ts#ordering
```
</CH.Code>

It is guaranteed that [the invocation on line `1`](focus://1) will execute before [the invocation on line `2`](focus://2).
It is not guaranteed though that [invocation `2`](focus://2) will be executed immediately after [invocation `1`](focus://1), as invocations coming from other handlers/sources, could interleave these two calls.
</CH.Section>
```typescript
CODE_LOAD::ts/src/develop/service_communication.ts#ordering
```

It is guaranteed that call A will execute before call B.
It is not guaranteed though that call B will be executed immediately after call A, as invocations coming from other handlers/sources, could interleave these two calls.
</Admonition>
Loading

0 comments on commit 1fe5999

Please sign in to comment.