Skip to content
Merged
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
2 changes: 1 addition & 1 deletion docs/advanced/adapters.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ adapter:
```

<Info>
For retry behavior, dead-letter queues, and full config reference, see the [Queue module](/workers/iii-queue).
For retry behavior, dead-letter queues, and full config reference, see the [Queue worker](/workers/iii-queue).
</Info>

---
Expand Down
10 changes: 5 additions & 5 deletions docs/advanced/architecture.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ graph TD
Reg[Worker<br/>Registry]
subgraph "Core Modules"
API[RestApiModule]
Stream[StreamModule]
Log[OtelModule]
Queue[QueueModule]
Cron[CronModule]
API[iii-http]
Stream[iii-stream]
Log[iii-observability]
Queue[iii-queue]
Cron[iii-cron]
end
end
Expand Down
2 changes: 1 addition & 1 deletion docs/advanced/protocol.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ Configure a trigger that maps to a function:
// Trigger-specific configuration
// For 'http': { api_path: '/path', http_method: 'GET' }
// For 'durable:subscriber': { topic: 'topic.name' }
// For 'cron': { expression: '0 * * * *' }
// For 'cron': { expression: '0 0 * * * * *' }
// For 'log': { level: 'error' }
}
}
Expand Down
41 changes: 22 additions & 19 deletions docs/examples/cron.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ iii.registerFunction(
iii.registerTrigger({
type: 'cron',
function_id: 'cron.periodic_job',
config: { expression: '* * * * *' }, // every minute
config: { expression: '0 * * * * * *' }, // every minute
})
```

Expand Down Expand Up @@ -76,7 +76,7 @@ iii.register_function("cron.periodic_job", periodic_job)
iii.register_trigger({
"type": "cron",
"function_id": "cron.periodic_job",
"config": {"expression": "* * * * *"}, # every minute
"config": {"expression": "0 * * * * * *"}, # every minute
})
```

Expand All @@ -90,7 +90,7 @@ use serde_json::json;
let iii = register_worker("ws://127.0.0.1:49134", InitOptions::default());

iii.register_function((RegisterFunctionMessage::with_id("cron.periodic_job".into()), |_input| async move {
let logger = Logger());
let logger = Logger::new();

logger.info("Periodic job fired", None);

Expand All @@ -106,7 +106,7 @@ iii.register_function((RegisterFunctionMessage::with_id("cron.periodic_job".into
});

iii.register_trigger(RegisterTriggerInput { trigger_type: "cron".into(), function_id: "cron.periodic_job".into(), config: json!({
"expression": "* * * * *",
"expression": "0 * * * * * *",
}), metadata: None })?;
```

Expand Down Expand Up @@ -161,7 +161,7 @@ use iii_sdk::{Logger, RegisterFunctionMessage, RegisterTriggerInput};
use serde_json::json;

iii.register_function((RegisterFunctionMessage::with_id("job.handle_tick".into()), |input| async move {
let logger = Logger());
let logger = Logger::new();

logger.info("Periodic job processed", Some(input));
Ok(json!(null))
Expand Down Expand Up @@ -224,7 +224,7 @@ iii.registerFunction(
iii.registerTrigger({
type: 'cron',
function_id: 'cron.orders_sweep',
config: { expression: '*/5 * * * *' },
config: { expression: '0 */5 * * * * *' },
})
```

Expand Down Expand Up @@ -269,7 +269,7 @@ def orders_sweep(_data) -> None:
logger.info("Sweep complete", {"checked": len(orders), "swept": swept})

iii.register_function("cron.orders_sweep", orders_sweep)
iii.register_trigger({"type": "cron", "function_id": "cron.orders_sweep", "config": {"expression": "*/5 * * * *"}})
iii.register_trigger({"type": "cron", "function_id": "cron.orders_sweep", "config": {"expression": "0 */5 * * * * *"}})
```

</Tab>
Expand All @@ -280,7 +280,7 @@ use iii_sdk::{Logger, TriggerRequest, TriggerAction, RegisterFunctionMessage, Re
use serde_json::json;

iii.register_function((RegisterFunctionMessage::with_id("cron.orders_sweep".into()), |_input| async move {
let logger = Logger());
let logger = Logger::new();

let orders_val = iii.trigger(TriggerRequest::new("state::list", json!({ "scope": "orders" }))).await?;
let orders = orders_val.as_array().cloned().unwrap_or_default();
Expand Down Expand Up @@ -315,34 +315,37 @@ iii.register_function((RegisterFunctionMessage::with_id("cron.orders_sweep".into
Ok(json!(null))
});

iii.register_trigger(RegisterTriggerInput { trigger_type: "cron".into(), function_id: "cron.orders_sweep".into(), config: json!({ "expression": "*/5 * * * *" }), metadata: None })?;
iii.register_trigger(RegisterTriggerInput { trigger_type: "cron".into(), function_id: "cron.orders_sweep".into(), config: json!({ "expression": "0 */5 * * * * *" }), metadata: None })?;
```

</Tab>
</Tabs>

## Cron expression format

iii uses a six-field extended cron format. The optional leading field is seconds.
iii supports six- or seven-field cron expressions: `second minute hour day month weekday [year]` (year is optional).

```
┌──────────── second (0-59, optional)
┌──────────── second (0-59)
│ ┌────────── minute (0-59)
│ │ ┌──────── hour (0-23)
│ │ │ ┌────── day of month (1-31)
│ │ │ │ ┌──── month (1-12)
│ │ │ │ │ ┌── day of week (0-7)
│ │ │ │ │ │
* * * * * *
│ │ │ │ │ ┌── day of week (0-7, Sun=0 or 7)
│ │ │ │ │ │ ┌ year (optional)
│ │ │ │ │ │ │
* * * * * * *
```

| Expression | Meaning |
|---|---|
| `* * * * *` | Every minute |
| `0 * * * *` | Every hour |
| `0 9 * * 1-5` | 09:00 on weekdays |
| `*/5 * * * *` | Every 5 minutes |
| `0/5 * * * * *` | Every 5 seconds (with seconds field) |
| `0 * * * * *` | Every minute (6-field) |
| `0 0 * * * *` | Every hour (6-field) |
| `0 * * * * * *` | Every minute (7-field) |
| `0 0 * * * * *` | Every hour (7-field) |
| `0 0 9 * * 1-5 *` | 09:00 on weekdays |
| `0 */5 * * * * *` | Every 5 minutes |
| `*/5 * * * * * *` | Every 5 seconds |

## Key concepts

Expand Down
6 changes: 3 additions & 3 deletions docs/examples/multi-trigger.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ iii.registerTrigger({
iii.registerTrigger({
type: 'cron',
function_id: 'orders.handle',
config: { expression: '* * * * *' },
config: { expression: '* * * * * * *' },
})
```

Expand Down Expand Up @@ -212,7 +212,7 @@ iii.register_trigger({"type": "http", "function_id": "orders.handle",
iii.register_trigger({"type": "durable:subscriber", "function_id": "orders.handle",
"config": {"topic": "order.created"}})
iii.register_trigger({"type": "cron", "function_id": "orders.handle",
"config": {"expression": "* * * * *"}})
"config": {"expression": "* * * * * * *"}})
```

</Tab>
Expand Down Expand Up @@ -331,7 +331,7 @@ iii.register_trigger(RegisterTriggerInput {
iii.register_trigger(RegisterTriggerInput {
trigger_type: "cron".into(),
function_id: "orders.handle".into(),
config: json!({ "expression": "* * * * *" }),
config: json!({ "expression": "* * * * * * *" }),
metadata: None,
})?;
```
Expand Down
6 changes: 3 additions & 3 deletions docs/examples/state-management.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ iii.registerFunction(
iii.registerTrigger({
type: 'cron',
function_id: 'cron.orders_audit',
config: { expression: '*/5 * * * *' },
config: { expression: '0 */5 * * * * *' },
})
```

Expand Down Expand Up @@ -316,7 +316,7 @@ def orders_audit(_data) -> None:


iii.register_function("cron.orders_audit", orders_audit)
iii.register_trigger({"type": "cron", "function_id": "cron.orders_audit", "config": {"expression": "*/5 * * * *"}})
iii.register_trigger({"type": "cron", "function_id": "cron.orders_audit", "config": {"expression": "0 */5 * * * * *"}})
```

</Tab>
Expand Down Expand Up @@ -364,7 +364,7 @@ iii.register_function(
iii.register_trigger(RegisterTriggerInput {
trigger_type: "cron".into(),
function_id: "cron.orders_audit".into(),
config: json!({ "expression": "*/5 * * * *" }),
config: json!({ "expression": "0 */5 * * * * *" }),
metadata: None,
})?;
```
Expand Down
10 changes: 5 additions & 5 deletions docs/examples/todo-app.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ graph LR
Browser["Browser (iii-browser-sdk)"] -->|"single WebSocket"| RBAC["RBAC Port :3111"]
RBAC -->|"auth + expose"| Engine["iii Engine"]
APIWorker["API Worker (iii-sdk)"] -->|"ws :49134"| Engine
Engine -->|"stream ops"| Stream["StreamModule :3112 (file-based KvStore)"]
Engine -->|"stream ops"| Stream["iii-stream :3112 (file-based KvStore)"]
Engine -->|"stream change events"| Browser
```

Expand Down Expand Up @@ -61,10 +61,10 @@ workers:
| --- | --- | --- |
| **iii-worker-manager** | 49134 | Internal port. The API worker connects here to register functions. |
| **iii-worker-manager (RBAC)** | 3111 | Public-facing port. The browser connects here. RBAC controls which functions are exposed and runs an auth function on every new connection. |
| **ExecModule** | — | Runs `pnpm dev` to start the API worker process. |
| **StreamModule** | 3112 | Manages stream state with a file-based KvStore adapter. The engine routes `stream::get`, `stream::set`, `stream::delete`, and `stream::list` to this module. |
| **iii-exec** | — | Runs `pnpm dev` to start the API worker process. |
| **iii-stream** | 3112 | Manages stream state with a file-based KvStore adapter. The engine routes `stream::get`, `stream::set`, `stream::delete`, and `stream::list` to this module. |

The RBAC configuration on port `3111` references `todo-project::auth-function` and explicitly lists the five functions the browser is allowed to call. See [Worker RBAC](/docs/how-to/worker-rbac) for the full reference.
The RBAC configuration on port `3111` references `todo-project::auth-function` and explicitly lists the five functions the browser is allowed to call. See [Worker RBAC](/how-to/worker-rbac) for the full reference.

## Backend

Expand Down Expand Up @@ -381,6 +381,6 @@ All CRUD operations (`addTodo`, `toggleTodo`, `deleteTodo`) call `iii.trigger` w

- **Single connection** — The browser opens one WebSocket to the RBAC port. Function calls and real-time stream events flow over the same connection.
- **No HTTP routes** — The API worker registers plain iii functions. The browser invokes them directly via `iii.trigger`. There is no REST layer.
- **RBAC** — The engine's iii-worker-manager supports auth functions, expose lists, and middleware. This example uses a simple auth function that creates a session. See [Worker RBAC](/docs/how-to/worker-rbac) for the full reference.
- **RBAC** — The engine's iii-worker-manager supports auth functions, expose lists, and middleware. This example uses a simple auth function that creates a session. See [Worker RBAC](/how-to/worker-rbac) for the full reference.
- **Engine-managed streams** — The `iii-stream` worker handles persistence (file-based KvStore in this example). The API worker reads and writes through `stream::*` function triggers — no custom stream implementation required.
- **Session isolation** — The auth function returns a `function_registration_prefix`. The engine prefixes every function registered by that browser session, so multiple clients can register `ui::on-todo-change` without colliding.
4 changes: 2 additions & 2 deletions docs/how-to/expose-http-endpoint.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Make sure `iii-config.yaml` has the REST API worker enabled:
- name: iii-http
config:
port: 3111
host: localhost
host: 127.0.0.1
default_timeout: 30000
concurrency_request_limit: 1024
cors:
Expand Down Expand Up @@ -142,7 +142,7 @@ iii.register_trigger(RegisterTriggerInput {
### 4. Try it

```bash
curl -X POST http://localhost:3111/users \
curl -X POST http://127.0.0.1:3111/users \
-H "Content-Type: application/json" \
-d '{"name": "Alice", "email": "alice@example.com"}'
```
Expand Down
2 changes: 1 addition & 1 deletion docs/how-to/schedule-cron-task.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ iii.register_trigger(RegisterTriggerInput {
</Tab>
</Tabs>

This runs the Function every second. The `expression` field uses a 7-field cron format with seconds support (`second minute hour day month weekday year`).
This runs the Function every second. The `expression` field uses a 7-field cron format (`second minute hour day month weekday year`).

### Common schedules

Expand Down
4 changes: 2 additions & 2 deletions docs/how-to/stream-realtime-data.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ workers:
- name: iii-stream
config:
port: ${STREAM_PORT:3112}
host: localhost
host: 127.0.0.1
adapter:
name: kv
config:
Expand Down Expand Up @@ -253,7 +253,7 @@ println!("Messages: {:?}", messages);
Clients connect to the stream WebSocket endpoint to receive live updates:

```javascript title="client.js"
const ws = new WebSocket('ws://localhost:3112/stream/chat/room-123')
const ws = new WebSocket('ws://127.0.0.1:3112/stream/chat/room-123')

ws.onmessage = (event) => {
const update = JSON.parse(event.data)
Expand Down
6 changes: 3 additions & 3 deletions docs/how-to/trigger-actions.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -644,7 +644,7 @@ iii.registerFunction('etl::extract', async () => {
iii.registerTrigger({
type: 'cron',
function_id: 'etl::extract',
config: { expression: '0 * * * *' },
config: { expression: '0 0 * * * * *' },
})
```
</Tab>
Expand Down Expand Up @@ -681,7 +681,7 @@ fn = iii.register_function("etl::extract", extract)
iii.register_trigger({
"type": "cron",
"function_id": fn.id,
"config": {"expression": "0 * * * *"},
"config": {"expression": "0 0 * * * * *"},
})
```
</Tab>
Expand Down Expand Up @@ -727,7 +727,7 @@ iii.register_function(reg);
iii.register_trigger(RegisterTriggerInput {
trigger_type: "cron".into(),
function_id: "etl::extract".into(),
config: json!({ "expression": "0 * * * *" }),
config: json!({ "expression": "0 0 * * * * *" }),
metadata: None,
})?;
```
Expand Down
8 changes: 4 additions & 4 deletions docs/how-to/use-functions-and-triggers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,7 @@ iii.registerFunction('math::aggregation', async () => {
iii.registerTrigger({
type: 'cron',
function_id: 'math::aggregation',
config: { expression: '0 */30 * * * *' }, // every 30 minutes
config: { expression: '0 */30 * * * * *' }, // every 30 minutes
});
```
</Tab>
Expand All @@ -502,7 +502,7 @@ iii.register_function("math::aggregation", aggregation)
iii.register_trigger({
"type": "cron",
"function_id": "math::aggregation",
"config": {"expression": "0 */30 * * * *"}, # every 30 minutes
"config": {"expression": "0 */30 * * * * *"}, # every 30 minutes
})
```
</Tab>
Expand Down Expand Up @@ -532,7 +532,7 @@ iii.register_function(reg);
iii.register_trigger(RegisterTriggerInput {
trigger_type: "cron".into(),
function_id: "math::aggregation".into(),
config: json!({ "expression": "0 */30 * * * *" }), // every 30 minutes
config: json!({ "expression": "0 */30 * * * * *" }), // every 30 minutes
metadata: None,
})?;
```
Expand Down Expand Up @@ -620,7 +620,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
Node `trigger({ function_id: 'iii::durable::publish', payload: { topic: 'user.created', data: {...} } })`,
Python `trigger({'function_id': 'iii::durable::publish', 'payload': {'topic': 'user.created', 'data': {...}}})`,
Rust `trigger(TriggerRequest::new("iii::durable::publish", json!({"topic": "user.created", "data": {...}})))`.
See the [Queue module](/workers/iii-queue) for details.
See the [Queue worker](/workers/iii-queue) for details.
</Info>

## Trigger Types
Expand Down
2 changes: 1 addition & 1 deletion docs/how-to/use-iii-in-the-browser.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ iii.registerFunction('metrics::collect', async () => {
iii.registerTrigger({
type: 'cron',
function_id: 'metrics::collect',
config: { expression: '*/5 * * * * *' },
config: { expression: '*/5 * * * * * *' },
})
```

Expand Down
Loading