# Reactor Pattern

## Problem

A server must handle many concurrent I/O sources (network sockets, files, timers). Dedicating one thread per connection wastes resources and doesn't scale.

## Solution

Use a single-threaded **event loop** that demultiplexes I/O events. The reactor waits for events on all registered sources, then dispatches each ready event to the appropriate handler. Handlers must be non-blocking to avoid stalling the loop.

## When to Use

- High-concurrency servers with many idle connections (web servers, chat servers)
- I/O-bound applications where most time is spent waiting
- When thread-per-connection is too expensive
- Event-driven GUI or game loop architectures

## When to Avoid

- CPU-bound workloads (the single-threaded loop becomes a bottleneck)
- When handlers require long-running synchronous computation
- Simple scripts with one or two I/O operations

## Pseudocode

```
reactor = EventLoop()

function on_connection(socket):
    print("New connection from " + socket.address)
    reactor.register(socket, READ, on_data)

function on_data(socket):
    data = socket.read()
    if data:
        print("Received: " + data)
        socket.write("Echo: " + data)
    else:
        socket.close()

reactor.register(server_socket, ACCEPT, on_connection)
reactor.run_forever()
```

## Python

```python
import asyncio

async def handle_client(reader: asyncio.StreamReader, writer: asyncio.StreamWriter) -> None:
    addr = writer.get_extra_info("peername")
    print(f"[Reactor] New connection from {addr}")

    while True:
        data = await reader.read(1024)
        if not data:
            break
        message = data.decode().strip()
        print(f"[Reactor] Received: {message}")
        response = f"Echo: {message}\n"
        writer.write(response.encode())
        await writer.drain()

    print(f"[Reactor] Connection closed: {addr}")
    writer.close()
    await writer.wait_closed()

async def client_simulation(port: int) -> None:
    """Simulate a client for demonstration."""
    await asyncio.sleep(0.1)  # wait for server to start
    reader, writer = await asyncio.open_connection("127.0.0.1", port)

    messages = ["Hello", "World", "Reactor Pattern"]
    for msg in messages:
        writer.write(f"{msg}\n".encode())
        await writer.drain()
        data = await reader.readline()
        print(f"[Client] Got: {data.decode().strip()}")

    writer.close()
    await writer.wait_closed()

async def main() -> None:
    port = 18888
    server = await asyncio.start_server(handle_client, "127.0.0.1", port)
    print(f"[Reactor] Server listening on port {port}")

    # Run a simulated client
    client_task = asyncio.create_task(client_simulation(port))
    await client_task

    server.close()
    await server.wait_closed()
    print("[Reactor] Server shut down.")

if __name__ == "__main__":
    asyncio.run(main())
```

## Go

```go
package main

import (
	"fmt"
	"time"
)

// Event types
type EventType int

const (
	EventTimer EventType = iota
	EventData
	EventShutdown
)

type Event struct {
	Type    EventType
	Source  string
	Payload string
}

// Handler function type
type Handler func(Event)

// Reactor demultiplexes events using Go's select
func reactor(events <-chan Event, handlers map[EventType]Handler, done chan<- bool) {
	fmt.Println("[Reactor] Event loop started")
	for {
		select {
		case evt := <-events:
			if evt.Type == EventShutdown {
				fmt.Println("[Reactor] Shutting down")
				done <- true
				return
			}
			if handler, ok := handlers[evt.Type]; ok {
				handler(evt)
			} else {
				fmt.Printf("[Reactor] No handler for event type %d\n", evt.Type)
			}
		}
	}
}

func main() {
	events := make(chan Event, 100)
	done := make(chan bool)

	handlers := map[EventType]Handler{
		EventTimer: func(e Event) {
			fmt.Printf("[Handler] Timer event from %s: %s\n", e.Source, e.Payload)
		},
		EventData: func(e Event) {
			fmt.Printf("[Handler] Data event from %s: %s\n", e.Source, e.Payload)
		},
	}

	go reactor(events, handlers, done)

	// Simulate event sources
	go func() {
		for i := 0; i < 3; i++ {
			events <- Event{Type: EventTimer, Source: "timer-1", Payload: fmt.Sprintf("tick %d", i)}
			time.Sleep(100 * time.Millisecond)
		}
	}()

	go func() {
		for i := 0; i < 3; i++ {
			events <- Event{Type: EventData, Source: "sensor-1", Payload: fmt.Sprintf("reading %d", i*10)}
			time.Sleep(150 * time.Millisecond)
		}
	}()

	time.Sleep(600 * time.Millisecond)
	events <- Event{Type: EventShutdown}
	<-done
	fmt.Println("Done.")
}
```

## JavaScript

```javascript
// JavaScript's runtime IS a reactor pattern.
// This demonstrates the concept explicitly.

class Reactor {
  constructor() {
    this.handlers = new Map();
    this.running = false;
  }

  register(eventType, handler) {
    if (!this.handlers.has(eventType)) {
      this.handlers.set(eventType, []);
    }
    this.handlers.get(eventType).push(handler);
    console.log(`[Reactor] Registered handler for '${eventType}'`);
  }

  dispatch(eventType, payload) {
    const handlers = this.handlers.get(eventType) || [];
    if (handlers.length === 0) {
      console.log(`[Reactor] No handler for '${eventType}'`);
      return;
    }
    for (const handler of handlers) {
      // Non-blocking: schedule via microtask
      queueMicrotask(() => handler(payload));
    }
  }
}

const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

async function main() {
  const reactor = new Reactor();

  // Register handlers
  reactor.register("connection", (data) => {
    console.log(`[Handler] New connection from ${data.address}`);
  });

  reactor.register("data", (data) => {
    console.log(`[Handler] Data received: ${data.message}`);
  });

  reactor.register("timer", (data) => {
    console.log(`[Handler] Timer tick: ${data.tick}`);
  });

  // Simulate events arriving over time
  console.log("[Reactor] Event loop running...");

  reactor.dispatch("connection", { address: "192.168.1.1" });
  await sleep(50);

  for (let i = 0; i < 3; i++) {
    reactor.dispatch("timer", { tick: i });
    reactor.dispatch("data", { message: `payload-${i}` });
    await sleep(100);
  }

  await sleep(50);
  console.log("[Reactor] Shutdown.");
}

main();
```

## Related Patterns

- **Observer** — the reactor dispatches events to handlers; handler registration is an application of the observer pattern.
- **Future/Promise** — async operations initiated in a reactor handler return futures; the reactor event loop resolves them.
