Skip to content

Commit 303ee25

Browse files
committed
Update ev docs
1 parent 83ba3cb commit 303ee25

File tree

1 file changed

+90
-2
lines changed
  • src/routes/docs/architecture/event-loop

1 file changed

+90
-2
lines changed

src/routes/docs/architecture/event-loop/+page.md

Lines changed: 90 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,91 @@ reader.read() ──► StreamRead(callback_id, stream_id)
296296

297297
---
298298

299+
## Two Loops Architecture
300+
301+
There are actually **two separate loops** that work together:
302+
303+
### 1. Scheduler Loop (background task)
304+
305+
Runs continuously in the background, spawning async tasks:
306+
307+
```rust
308+
// runtime/mod.rs - run_event_loop()
309+
async fn run_event_loop(scheduler_rx, callback_tx, ops) {
310+
loop {
311+
select! {
312+
msg = scheduler_rx.recv() => {
313+
match msg {
314+
FetchStreaming(id, req) => {
315+
tokio::spawn(async {
316+
let result = ops.handle(Fetch(req)).await;
317+
callback_tx.send(FetchSuccess(id, result));
318+
});
319+
}
320+
ScheduleTimeout(id, ms) => { /* spawn timer */ }
321+
}
322+
}
323+
}
324+
}
325+
}
326+
```
327+
328+
### 2. Execution Loop (in exec())
329+
330+
Polls for results and checks termination conditions:
331+
332+
```rust
333+
// worker.rs - exec()
334+
async fn exec(&mut self, task: Task) {
335+
self.trigger_fetch_event(request); // Start JS execution
336+
337+
for iteration in 0..5000 {
338+
// Check termination (timeout, CPU limit)
339+
if wall_guard.was_triggered() {
340+
return Err(WallClockTimeout);
341+
}
342+
343+
// Process available callbacks (NON-BLOCKING)
344+
self.runtime.process_callbacks();
345+
346+
// Check if response is ready
347+
if response_ready { break; }
348+
349+
// Yield to let scheduler run
350+
tokio::time::sleep(duration).await;
351+
}
352+
}
353+
```
354+
355+
### Why Two Loops?
356+
357+
```
358+
┌──────────────────────────────────────────────────────────────────┐
359+
│ exec() loop │
360+
│ │
361+
│ ┌─────────┐ ┌───────────────────┐ ┌─────────┐ │
362+
│ │ Check │───►│ process_callbacks │───►│ Check │───► sleep │
363+
│ │ timeout │ │ (try_recv) │ │ ready │ │
364+
│ └─────────┘ └───────────────────┘ └─────────┘ │
365+
│ │ ▲ │
366+
│ │ │ results │
367+
│ │ │ │
368+
│ ▼ │ │
369+
│ ┌──────────────────────────────────────────────────────────┐ │
370+
│ │ Scheduler (background task) │ │
371+
│ │ │ │
372+
│ │ recv() ──► spawn fetch ──► await reqwest ──► send() │ │
373+
│ └──────────────────────────────────────────────────────────┘ │
374+
└──────────────────────────────────────────────────────────────────┘
375+
```
376+
377+
- **Scheduler**: Handles async I/O (blocking `recv().await`)
378+
- **exec() loop**: Polls results, enforces timeouts, controls V8
379+
380+
The `sleep().await` in exec() is crucial - it yields control to tokio, allowing the scheduler to make progress on pending operations.
381+
382+
---
383+
299384
## Integration Points
300385

301386
### process_callbacks()
@@ -311,7 +396,7 @@ pub fn process_callbacks(&mut self) {
311396
// 1. V8 internal tasks (Atomics, WebAssembly, etc.)
312397
while v8::Platform::pump_message_loop(platform, scope, false) {}
313398

314-
// 2. Our custom callbacks
399+
// 2. Our custom callbacks (NON-BLOCKING: try_recv returns immediately)
315400
while let Ok(msg) = self.callback_rx.try_recv() {
316401
match msg { /* ... */ }
317402
}
@@ -321,6 +406,8 @@ pub fn process_callbacks(&mut self) {
321406
}
322407
```
323408

409+
**Important**: `try_recv()` is non-blocking - it returns `Err(Empty)` immediately if no messages are available. This allows the exec() loop to check for timeouts and response readiness without waiting.
410+
324411
### OperationsHandler
325412

326413
All I/O goes through the Runner's `OperationsHandler`:
@@ -348,7 +435,8 @@ This allows the Runner to:
348435

349436
| File | Purpose |
350437
| ------------------------------------------------------ | --------------------------------------------- |
351-
| `openworkers-runtime-v8/src/runtime/mod.rs` | Runtime struct, event loop, process_callbacks |
438+
| `openworkers-runtime-v8/src/worker.rs` | Worker struct, exec() loop |
439+
| `openworkers-runtime-v8/src/runtime/mod.rs` | Runtime struct, scheduler, process_callbacks |
352440
| `openworkers-runtime-v8/src/runtime/bindings/` | Native V8 functions |
353441
| `openworkers-runtime-v8/src/runtime/stream_manager.rs` | Stream coordination |
354442
| `openworkers-core/src/ops.rs` | Operation, OperationResult enums |

0 commit comments

Comments
 (0)