Skip to content
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
60 changes: 59 additions & 1 deletion src/content/docs/durable-objects/api/alarms.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ sidebar:
order: 8
---

import { Type, GlossaryTooltip } from "~/components";
import { Type, GlossaryTooltip, Tabs, TabItem } from "~/components";

## Background

Expand Down Expand Up @@ -84,6 +84,10 @@ This example shows how to both set alarms with the `setAlarm(timestamp)` method
- If an unexpected error terminates the Durable Object, the `alarm()` handler may be re-instantiated on another machine.
- Following a short delay, the `alarm()` handler will run from the beginning on the other machine.

<Tabs>

<TabItem label="JavaScript" icon="seti:javascript">

```js
import { DurableObject } from "cloudflare:workers";

Expand Down Expand Up @@ -115,8 +119,47 @@ export class AlarmExample extends DurableObject {
}
```

</TabItem>

<TabItem label="Python" icon="seti:python">

```python
from workers import DurableObject, WorkerEntrypoint

class Default(WorkerEntrypoint):
async def fetch(self, request):
return await self.env.ALARM_EXAMPLE.getByName("foo").fetch(request)

SECONDS = 1000

class AlarmExample(DurableObject):
def __init__(self, ctx, env):
super().__init__(ctx, env)
self.storage = ctx.storage

async def fetch(self, request):
# If there is no alarm currently set, set one for 10 seconds from now
current_alarm = await self.storage.getAlarm()
if current_alarm is None:
self.storage.setAlarm(Date.now() + 10 * SECONDS)

async def alarm(self):
# The alarm handler will be invoked whenever an alarm fires.
# You can use this to do work, read from the Storage API, make HTTP calls
# and set future alarms to run using self.storage.setAlarm() from within this handler.
pass
```

</TabItem>

</Tabs>

The following example shows how to use the `alarmInfo` property to identify if the alarm event has been attempted before.

<Tabs>

<TabItem label="JavaScript" icon="seti:javascript">

```js
class MyDurableObject extends DurableObject {
async alarm(alarmInfo) {
Expand All @@ -129,6 +172,21 @@ class MyDurableObject extends DurableObject {
}
```

</TabItem>

<TabItem label="Python" icon="seti:python">

```python
class MyDurableObject(DurableObject):
async def alarm(self, alarm_info):
if alarm_info and alarm_info.get('retryCount', 0) != 0:
print(f"This alarm event has been attempted {alarm_info.get('retryCount')} times before.")
```

</TabItem>

</Tabs>

## Related resources

- Understand how to [use the Alarms API](/durable-objects/examples/alarms-api/) in an end-to-end example.
Expand Down
21 changes: 20 additions & 1 deletion src/content/docs/durable-objects/api/base.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import { Render, Tabs, TabItem, GlossaryTooltip, Type, MetaInfo, TypeScriptExamp

The `DurableObject` base class is an abstract class which all Durable Objects inherit from. This base class provides a set of optional methods, frequently referred to as handler methods, which can respond to events, for example a webSocketMessage when using the [WebSocket Hibernation API](/durable-objects/best-practices/websockets/#websocket-hibernation-api). To provide a concrete example, here is a Durable Object `MyDurableObject` which extends `DurableObject` and implements the fetch handler to return "Hello, World!" to the calling Worker.

<TypeScriptExample>
<Tabs>

<TypeScriptExample omitTabs={true}>
```ts
export class MyDurableObject extends DurableObject {
constructor(ctx: DurableObjectState, env: Env) {
Expand All @@ -23,6 +25,23 @@ export class MyDurableObject extends DurableObject {
```
</TypeScriptExample>

<TabItem label="Python" icon="seti:python">

```python
from workers import DurableObject, Response

class MyDurableObject(DurableObject):
def __init__(self, ctx, env):
super().__init__(ctx, env)

async def fetch(self, request):
return Response("Hello, World!")
```

</TabItem>

</Tabs>

## Methods

### `fetch`
Expand Down
164 changes: 162 additions & 2 deletions src/content/docs/durable-objects/api/container.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ It is likely preferable to use the official `Container` class, which provides he
a more idiomatic API for working with containers on top of Durable Objects.
:::

<TypeScriptExample filename="index.ts">
<Tabs>

<TypeScriptExample filename="index.ts" omitTabs={true}>
```ts
export class MyDurableObject extends DurableObject {
constructor(ctx: DurableObjectState, env: Env) {
Expand All @@ -42,24 +44,63 @@ export class MyDurableObject extends DurableObject {
```
</TypeScriptExample>

<TabItem label="Python" icon="seti:python">

```python
from workers import DurableObject

class MyDurableObject(DurableObject):
def __init__(self, ctx, env):
super().__init__(ctx, env)

# boot the container when starting the DO
async def start_container():
self.ctx.container.start()
self.ctx.blockConcurrencyWhile(start_container)
```

</TabItem>

</Tabs>


## Attributes

### `running`

`running` returns `true` if the container is currently running. It does not ensure that the container has fully started and ready to accept requests.

<Tabs>

<TabItem label="JavaScript" icon="seti:javascript">

```js
this.ctx.container.running;
this.ctx.container.running;
```

</TabItem>

<TabItem label="Python" icon="seti:python">

```python
self.ctx.container.running
```

</TabItem>

</Tabs>

## Methods

### `start`

`start` boots a container. This method does not block until the container is fully started.
You may want to confirm the container is ready to accept requests before using it.

<Tabs>

<TabItem label="JavaScript" icon="seti:javascript">

```js
this.ctx.container.start({
env: {
Expand All @@ -70,6 +111,26 @@ this.ctx.container.start({
});
```

</TabItem>

<TabItem label="Python" icon="seti:python">

```python
from pyodide.ffi import to_js

self.ctx.container.start(
env = to_js({
"FOO": "bar",
}),
enableInternet = False,
entrypoint = to_js(["node", "server.js"]),
)
```

</TabItem>

</Tabs>

#### Parameters

- `options` (optional): An object with the following properties:
Expand All @@ -85,10 +146,26 @@ this.ctx.container.start({

`destroy` stops the container and optionally returns a custom error message to the `monitor()` error callback.

<Tabs>

<TabItem label="JavaScript" icon="seti:javascript">

```js
this.ctx.container.destroy("Manually Destroyed");
```

</TabItem>

<TabItem label="Python" icon="seti:python">

```python
self.ctx.container.destroy("Manually Destroyed")
```

</TabItem>

</Tabs>

#### Parameters

- `error` (optional): A string that will be sent to the error handler of the `monitor` method. This is useful for logging or debugging purposes.
Expand All @@ -101,11 +178,28 @@ this.ctx.container.destroy("Manually Destroyed");

`signal` sends an IPC signal to the container, such as SIGKILL or SIGTERM. This is useful for stopping the container gracefully or forcefully.

<Tabs>

<TabItem label="JavaScript" icon="seti:javascript">

```js
const SIGTERM = 15;
this.ctx.container.signal(SIGTERM);
```

</TabItem>

<TabItem label="Python" icon="seti:python">

```python
SIGTERM = 15
self.ctx.container.signal(SIGTERM)
```

</TabItem>

</Tabs>

#### Parameters

- `signal`: a number representing the signal to send to the container. This is typically a POSIX signal number, such as SIGTERM (15) or SIGKILL (9).
Expand All @@ -118,6 +212,10 @@ this.ctx.container.signal(SIGTERM);

`getTcpPort` returns a TCP port from the container. This can be used to communicate with the container over TCP and HTTP.

<Tabs>

<TabItem label="JavaScript" icon="seti:javascript">

```js
const port = this.ctx.container.getTcpPort(8080);
const res = await port.fetch("http://container/set-state", {
Expand All @@ -141,6 +239,38 @@ try {
}
```

</TabItem>

<TabItem label="Python" icon="seti:python">

```python
port = self.ctx.container.getTcpPort(8080)
res = await port.fetch(
"http://container/set-state",
body = initial_state,
method = "POST",
)
```

```python
from workers import Response

conn = self.ctx.container.getTcpPort(8080).connect('10.0.0.1:8080')
await conn.opened

try:
if request.body:
await request.body.pipeTo(conn.writable)
return Response(conn.readable)
except Exception as err:
print(f"Request body piping failed: {err}")
return Response("Failed to proxy request body", status=502)
```

</TabItem>

</Tabs>

#### Parameters

- `port` (number): a TCP port number to use for communication with the container.
Expand All @@ -154,6 +284,10 @@ try {
`monitor` returns a promise that resolves when a container exits and errors if a container errors. This is useful for setting up
callbacks to handle container status changes in your Workers code.

<Tabs>

<TabItem label="JavaScript" icon="seti:javascript">

```js
class MyContainer extends DurableObject {
constructor(ctx, env) {
Expand All @@ -173,6 +307,32 @@ class MyContainer extends DurableObject {
}
```

</TabItem>

<TabItem label="Python" icon="seti:python">

```python
from workers import DurableObject

class MyContainer(DurableObject):
def __init__(self, ctx, env):
super().__init__(ctx, env)

def on_container_exit():
print("Container exited")

# the "err" value can be customized by the destroy() method
async def on_container_error(err):
print(f"Container errored: {err}")

self.ctx.container.start()
self.ctx.container.monitor().then(on_container_exit).catch(on_container_error)
```

</TabItem>

</Tabs>

#### Parameters

- None
Expand Down
Loading
Loading