mirror of
https://github.com/ksyasuda/dotfiles.git
synced 2026-03-20 18:11:27 -07:00
188 lines
4.2 KiB
Markdown
188 lines
4.2 KiB
Markdown
## Container Class API
|
|
|
|
```typescript
|
|
import { Container } from "@cloudflare/containers";
|
|
|
|
export class MyContainer extends Container {
|
|
defaultPort = 8080;
|
|
requiredPorts = [8080];
|
|
sleepAfter = "30m";
|
|
enableInternet = true;
|
|
pingEndpoint = "/health";
|
|
envVars = {};
|
|
entrypoint = [];
|
|
|
|
onStart() { /* container started */ }
|
|
onStop() { /* container stopping */ }
|
|
onError(error: Error) { /* container error */ }
|
|
onActivityExpired(): boolean { /* timeout, return true to stay alive */ }
|
|
async alarm() { /* scheduled task */ }
|
|
}
|
|
```
|
|
|
|
## Routing
|
|
|
|
**getByName(id)** - Named instance for session affinity, per-user state
|
|
**getRandom()** - Random instance for load balancing stateless services
|
|
|
|
```typescript
|
|
const container = env.MY_CONTAINER.getByName("user-123");
|
|
const container = env.MY_CONTAINER.getRandom();
|
|
```
|
|
|
|
## Startup Methods
|
|
|
|
### start() - Basic start (8s timeout)
|
|
|
|
```typescript
|
|
await container.start();
|
|
await container.start({ envVars: { KEY: "value" } });
|
|
```
|
|
|
|
Returns when **process starts**, NOT when ports ready. Use for fire-and-forget.
|
|
|
|
### startAndWaitForPorts() - Recommended (20s timeout)
|
|
|
|
```typescript
|
|
await container.startAndWaitForPorts(); // Uses requiredPorts
|
|
await container.startAndWaitForPorts({ ports: [8080, 9090] });
|
|
await container.startAndWaitForPorts({
|
|
ports: [8080],
|
|
startOptions: { envVars: { KEY: "value" } }
|
|
});
|
|
```
|
|
|
|
Returns when **ports listening**. Use before HTTP/TCP requests.
|
|
|
|
**Port resolution:** explicit ports → requiredPorts → defaultPort → port 33
|
|
|
|
### waitForPort() - Wait for specific port
|
|
|
|
```typescript
|
|
await container.waitForPort(8080);
|
|
await container.waitForPort(8080, { timeout: 30000 });
|
|
```
|
|
|
|
## Communication
|
|
|
|
### fetch() - HTTP with WebSocket support
|
|
|
|
```typescript
|
|
// ✅ Supports WebSocket upgrades
|
|
const response = await container.fetch(request);
|
|
const response = await container.fetch("http://container/api", {
|
|
method: "POST",
|
|
body: JSON.stringify({ data: "value" })
|
|
});
|
|
```
|
|
|
|
**Use for:** All HTTP, especially WebSocket.
|
|
|
|
### containerFetch() - HTTP only (no WebSocket)
|
|
|
|
```typescript
|
|
// ❌ No WebSocket support
|
|
const response = await container.containerFetch(request);
|
|
```
|
|
|
|
**⚠️ Critical:** Use `fetch()` for WebSocket, not `containerFetch()`.
|
|
|
|
### TCP Connections
|
|
|
|
```typescript
|
|
const port = this.ctx.container.getTcpPort(8080);
|
|
const conn = port.connect();
|
|
await conn.opened;
|
|
|
|
if (request.body) await request.body.pipeTo(conn.writable);
|
|
return new Response(conn.readable);
|
|
```
|
|
|
|
### switchPort() - Change default port
|
|
|
|
```typescript
|
|
this.switchPort(8081); // Subsequent fetch() uses this port
|
|
```
|
|
|
|
## Lifecycle Hooks
|
|
|
|
### onStart()
|
|
|
|
Called when container process starts (ports may not be ready). Runs in `blockConcurrencyWhile` - no concurrent requests.
|
|
|
|
```typescript
|
|
onStart() {
|
|
console.log("Container starting");
|
|
}
|
|
```
|
|
|
|
### onStop()
|
|
|
|
Called when SIGTERM received. 15 minutes until SIGKILL. Use for graceful shutdown.
|
|
|
|
```typescript
|
|
onStop() {
|
|
// Save state, close connections, flush logs
|
|
}
|
|
```
|
|
|
|
### onError()
|
|
|
|
Called when container crashes or fails to start.
|
|
|
|
```typescript
|
|
onError(error: Error) {
|
|
console.error("Container error:", error);
|
|
}
|
|
```
|
|
|
|
### onActivityExpired()
|
|
|
|
Called when `sleepAfter` timeout reached. Return `true` to stay alive, `false` to stop.
|
|
|
|
```typescript
|
|
onActivityExpired(): boolean {
|
|
if (this.hasActiveConnections()) return true; // Keep alive
|
|
return false; // OK to stop
|
|
}
|
|
```
|
|
|
|
## Scheduling
|
|
|
|
```typescript
|
|
export class ScheduledContainer extends Container {
|
|
async fetch(request: Request) {
|
|
await this.schedule(Date.now() + 60000); // 1 minute
|
|
await this.schedule("2026-01-28T00:00:00Z"); // ISO string
|
|
return new Response("Scheduled");
|
|
}
|
|
|
|
async alarm() {
|
|
// Called when schedule fires (SQLite-backed, survives restarts)
|
|
}
|
|
}
|
|
```
|
|
|
|
**⚠️ Don't override `alarm()` directly when using `schedule()` helper.**
|
|
|
|
## State Inspection
|
|
|
|
### External state check
|
|
|
|
```typescript
|
|
const state = await container.getState();
|
|
// state.status: "starting" | "running" | "stopping" | "stopped"
|
|
```
|
|
|
|
### Internal state check
|
|
|
|
```typescript
|
|
export class MyContainer extends Container {
|
|
async fetch(request: Request) {
|
|
if (this.ctx.container.running) { ... }
|
|
}
|
|
}
|
|
```
|
|
|
|
**⚠️ Use `getState()` for external checks, `ctx.container.running` for internal.**
|