# Watcher (Hot Reload)
The **Watcher** provides hot-reload capability for Managers during development. It monitors Python source files for changes and automatically restarts the corresponding Manager when its file is modified.
> The Watcher is a **development-only** feature. It is not intended for production use.
---
## How it works
```mermaid
flowchart LR
FS["Filesystem changes"] -->|FileModifiedEvent| Obs["watchdog.observers.Observer"]
Obs --> WH["WatcherHandler
lookup component
by file path"]
WH --> T["Timer debounce
1 s dev
10 s prod"]
T --> RE["Restart Event → Router Queue"]
```
### Component tree
| Class | Role |
|----------------------|------------------------------------------------------------------|
| `Watcher` | Entry point — sets up `watchdog.observers.Observer`, schedules file paths |
| `WatcherHandler` | Handles `FileModifiedEvent`, debounces with a `Timer` |
| `WatcherHandlerComponent` | Dataclass: `(type: Type[ManagerBase], timer: Timer \| None)` |
### Debounce mechanism
When a file is saved (e.g. by an IDE that writes multiple times), multiple `FileModifiedEvent` can be emitted in rapid succession. The Watcher debounces by:
1. On first modification, starting a `Timer` with a delay.
2. On subsequent modifications before the timer fires, **cancelling** the old timer and starting a new one.
3. Only when the timer finally fires is the `Restart` event actually sent to the Router.
This prevents restarting the Manager multiple times during a single save operation.
---
## Starting the Watcher
```python
from edri import EDRI
edri = EDRI()
edri.add_component(MyManager(edri.router_queue))
edri.start_watcher()
edri.run()
```
The Watcher automatically detects which Python files define the added components and monitors them all.
---
## Restart behavior
When a file change is detected and the debounce timer expires:
1. The Watcher puts a `Restart(manager=ManagerClass)` event on the Router queue.
2. The Router dispatches it to every Manager subscribed to `Restart`. Each Manager's built-in `_restart` handler checks whether `event.manager` matches its own class and ignores the event otherwise.
3. The matching Manager **reloads its own source module** (`importlib.reload`), looks up the (possibly changed) class on the reloaded module, unsubscribes its events, starts a **fresh instance** of that class, and then exits.
Because the module is reloaded from disk, code changes in the Manager's file are picked up. The new Manager's `__init__` runs again, so any in-memory state is rebuilt from scratch. Configuration read from environment variables or external sources is also re-read on restart.
> **Important:** The `Restart` event carries the Manager **class type** (`manager=...`), not the instance. The restart is performed by the old Manager process itself — it reloads the class from disk and spawns the replacement before exiting; the Router only delivers the event.
---
## Timer delays
| Environment | Delay | Rationale |
|------------------|--------|--------------------------------------------------------------|
| `development` | 1 s | Fast feedback during active development |
| `production` | 10 s | Prevent rapid restart loops if something is writing files |
The delay is set based on `ENVIRONMENT` environment variable.
---
## Limitations
* Only Managers added via `edri.add_component(...)` are watched.
* The Watcher monitors the file that defines the Manager class. If the Manager depends on other modules that change, those changes are **not** detected unless those files also define a watched Manager.
* Route registrations (event subscriptions) are re-applied on restart because the new Manager instance re-registers them during initialization.
* The Watcher does **not** monitor files inside packages that are installed as dependencies (only project source files).
* There is no support for monitoring multiple files per component — only the file containing the Manager class is watched.
---
## Configuration
The Watcher uses **watchdog** under the hood. It is configured through environment variables:
| Variable | Effect on Watcher |
|---------------|---------------------------------------|
| `ENVIRONMENT` | Controls the debounce delay (1 vs 10) |
No additional environment variables are needed for basic operation.
---
## Related
* {doc}`/manager` — Manager lifecycle, including `after_start()` hook
* {doc}`/env` — `ENVIRONMENT` variable
* {doc}`/router` — how `Restart` events are routed