|
| 1 | +# Standalone Worker Process Control |
| 2 | + |
| 3 | +## Summary |
| 4 | + |
| 5 | +Add support for starting/stopping a user-specified worker command from the Standalone Settings page. The GUI will spawn the worker with `ABSURD_DATABASE_PATH` (current database path) and `ABSURD_DATABASE_EXTENSION_PATH` (bundled extension path) set, show the running PID, surface a crash indicator when the worker repeatedly exits unexpectedly, and stream recent worker logs. |
| 6 | + |
| 7 | +## Goals |
| 8 | + |
| 9 | +- Let users configure a worker command (e.g. `npx ...`, `uvx ...`) in Settings. |
| 10 | +- Allow start/stop control from Settings. |
| 11 | +- Display worker PID while running. |
| 12 | +- Display a crash indicator if the worker is crashing (rapid, repeated exits). |
| 13 | +- Pass required environment variables when starting the worker. |
| 14 | +- Capture and display recent worker logs (in-memory, capped). |
| 15 | + |
| 16 | +## Non-Goals |
| 17 | + |
| 18 | +- Managing auto-start on app launch beyond "start when command is set". |
| 19 | +- Managing multiple worker processes. |
| 20 | +- Persisting logs to disk or long-term log retention. |
| 21 | +- Bundling a worker binary with the app. |
| 22 | + |
| 23 | +## User Experience |
| 24 | + |
| 25 | +- Settings page shows a "Worker" card with: |
| 26 | + - Text input for a worker command. |
| 27 | + - Status line: "Running (PID ####)", "Stopped", or "Crashing". |
| 28 | + - Start/Stop button (disabled if no command is set). |
| 29 | + - Collapsible "Logs" section with a toggle; when open, display recent output. |
| 30 | +- Crash indicator appears if the worker exits unexpectedly multiple times within a short window (e.g., 3 exits within 60 seconds). |
| 31 | + |
| 32 | +### UI Layout (Settings) |
| 33 | + |
| 34 | +``` |
| 35 | +Settings |
| 36 | +------------------------------------------------------------ |
| 37 | +[Version Card] [Database Card] |
| 38 | +
|
| 39 | +[Migrations Card] |
| 40 | +
|
| 41 | +[Worker Card] |
| 42 | +------------------------------------------------------------ |
| 43 | +Worker |
| 44 | +Run a local worker process for this database. |
| 45 | +
|
| 46 | +Command [ npx absurd-worker.................. ] |
| 47 | +Status [ Running (PID 12345) | Stopped | Crashing ] |
| 48 | +
|
| 49 | +[ Start/Stop ] |
| 50 | +
|
| 51 | +[ Logs ▾ ] |
| 52 | +------------------------------------------------------------ |
| 53 | +12:01:22 [stdout] worker started |
| 54 | +12:01:23 [stderr] warning: ... |
| 55 | +... |
| 56 | +``` |
| 57 | + |
| 58 | +## Data Model & Persistence |
| 59 | + |
| 60 | +- Use `tauri_plugin_store` to persist worker configuration in a JSON store (e.g. `worker.json`). |
| 61 | +- Keys: |
| 62 | + - `worker_binary_path` (string, command line). |
| 63 | + |
| 64 | +## Backend Design (Tauri) |
| 65 | + |
| 66 | +### New State |
| 67 | + |
| 68 | +- `WorkerState` managed in `AppHandle`: |
| 69 | + - `binary_path: Mutex<Option<String>>` |
| 70 | + - `running: Mutex<Option<RunningWorker>>` |
| 71 | + - `crash_history: Mutex<VecDeque<Instant>>` |
| 72 | + - `log_buffer: Mutex<VecDeque<WorkerLogLine>>` |
| 73 | +- `RunningWorker`: |
| 74 | + - `pid: u32` |
| 75 | + - `child: tauri_plugin_shell::process::Child` |
| 76 | + - `rx: CommandEvent` receiver task handle |
| 77 | +- `WorkerLogLine`: |
| 78 | + - `timestamp: String` (formatted) |
| 79 | + - `stream: "stdout" | "stderr"` |
| 80 | + - `line: String` |
| 81 | + |
| 82 | +### New Commands |
| 83 | + |
| 84 | +- `get_worker_status` -> `{ configuredPath, running, pid, crashing }` |
| 85 | +- `set_worker_binary_path(path: String)` -> updated status |
| 86 | +- `start_worker()` -> updated status |
| 87 | +- `stop_worker()` -> updated status |
| 88 | +- `get_worker_logs` -> `{ lines: WorkerLogLine[] }` |
| 89 | +- `clear_worker_logs` -> `{ lines: WorkerLogLine[] }` (optional) |
| 90 | + |
| 91 | +### Spawn Behavior |
| 92 | + |
| 93 | +- Parse command into program + args (basic quoting supported). |
| 94 | +- Use `DatabaseHandle` to resolve the current `ABSURD_DATABASE_PATH`. |
| 95 | +- Expose a helper to resolve the bundled extension path from `db.rs` for `ABSURD_DATABASE_EXTENSION_PATH`. |
| 96 | +- Spawn using `tauri_plugin_shell`: |
| 97 | + - Command = configured program + args. |
| 98 | + - Env: |
| 99 | + - `ABSURD_DATABASE_PATH=<db_path>` |
| 100 | + - `ABSURD_DATABASE_EXTENSION_PATH=<extension_path>` |
| 101 | + - Capture stdout/stderr lines and append to `log_buffer`. |
| 102 | +- Track process exit: |
| 103 | + - If terminated while `start_worker` initiated and not explicitly stopped, record crash time. |
| 104 | + - Crash indicator = N exits within rolling window (e.g., 3 in 60s). |
| 105 | + - If command changes while running, stop the previous process and restart. |
| 106 | + - Attempt to start on app launch when a command is configured. |
| 107 | + |
| 108 | +### Stop Behavior |
| 109 | + |
| 110 | +- If running, send SIGTERM on Unix (fallback to kill on other platforms). |
| 111 | +- Clear `running` state. |
| 112 | +- Do not mark crash on user-initiated stop. |
| 113 | + |
| 114 | +## Frontend Design (Svelte) |
| 115 | + |
| 116 | +- Extend `SettingsInfo` or add a new API payload for worker status. |
| 117 | +- New UI section in `standalone/src/routes/settings/+page.svelte`: |
| 118 | + - Input bound to worker command. |
| 119 | + - Start/Stop button next to the status badge. |
| 120 | + - Toggleable logs section (collapsed by default). |
| 121 | + - When open, poll or subscribe to log updates from backend. |
| 122 | + - Status badge: |
| 123 | + - Running with PID. |
| 124 | + - Stopped. |
| 125 | + - Crashing (if `crashing === true`). |
| 126 | +- Refresh status on mount and after any start/stop/path changes. |
| 127 | + |
| 128 | +## Error Handling |
| 129 | + |
| 130 | +- Surface start/stop errors to the UI (e.g., toast or inline message). |
| 131 | +- If extension path cannot be resolved, block start and show error. |
| 132 | +- If log streaming fails, show a non-blocking message and keep controls active. |
| 133 | + |
| 134 | +## Testing |
| 135 | + |
| 136 | +- Backend unit tests for: |
| 137 | + - Parsing/persistence of stored worker path. |
| 138 | + - Crash indicator threshold logic. |
| 139 | +- Log buffer trimming to 500 lines. |
| 140 | +- Manual smoke test: |
| 141 | + - Set a valid worker path, start, verify PID. |
| 142 | + - Stop and verify state. |
| 143 | + - Use a dummy executable that exits immediately to trigger crash indicator. |
| 144 | + - Verify logs appear and cap at 500 lines. |
0 commit comments