File size: 4,665 Bytes
6a7089a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 | # Orchestration
This page describes the current orchestration layer in PinchTab: how the server launches, tracks, routes to, and stops browser instances.
## Scope
The orchestrator is part of server mode. It is responsible for:
- launching managed instances as child `pinchtab bridge` processes
- attaching externally managed Chrome instances when attach policy allows it
- tracking instance status and metadata
- routing tab-scoped requests to the owning managed instance
- stopping managed instances and cleaning up registry state
It does not execute browser actions directly. That work happens inside the bridge runtime.
## Current Runtime Shape
```mermaid
flowchart TD
S["PinchTab Server"] --> O["Orchestrator"]
O --> M1["Managed Instance"]
O --> M2["Managed Instance"]
O -.->|attach| A1["Attached External Instance"]
M1 --> B1["pinchtab bridge child"]
M2 --> B2["pinchtab bridge child"]
B1 --> C1["Chrome"]
B2 --> C2["Chrome"]
```
## Launch Flow
For a managed instance, the orchestration flow is:
```mermaid
flowchart LR
R["Start Request"] --> V["Validate profile + port"]
V --> W["Write child config"]
W --> P["Spawn pinchtab bridge"]
P --> H["Poll /health on loopback addresses"]
H --> S{"Healthy before timeout?"}
S -->|Yes| OK["Mark running"]
S -->|No| ER["Mark error"]
```
What the code does today:
- validates the profile name before launch
- allocates a port when one is not supplied
- prevents more than one active managed instance per profile
- prevents reusing a port already in use
- writes a child config file under the profile state directory
- launches `pinchtab bridge`
- polls `/health` on `127.0.0.1`, `::1`, and `localhost`
- moves the instance from `starting` to `running` or `error`
## Attach Flow
Attach is a separate path for an already running browser.
```mermaid
flowchart LR
R["POST /instances/attach"] --> P["Validate attach policy"]
P --> A["Register external instance"]
A --> L["Add to instance registry"]
```
Current attach behavior:
- requires `security.attach.enabled`
- validates the CDP URL against `security.attach.allowSchemes`
- validates the host against `security.attach.allowHosts`
- registers the instance as `attached: true`
- does not start or stop an external Chrome process
## Routing Model
The orchestrator is also the routing layer for multi-instance server mode.
```mermaid
flowchart LR
R["Tab-scoped request"] --> T["Resolve tab owner"]
T --> C["Locator cache"]
C -->|hit| P["Proxy to instance port"]
C -->|miss| F["Fetch /tabs from running instances"]
F --> P
```
Today, tab routing works like this:
- for routes such as `/tabs/{id}/navigate` and `/tabs/{id}/action`, the server resolves which instance owns the tab
- it first tries the instance locator cache
- on cache miss, it falls back to scanning running instances through `/tabs`
- after resolution, it proxies the request to the owning bridge instance
This keeps the public server API stable while the bridge instances remain isolated.
Important limitation:
- this routing path is fully shaped around managed bridge-backed instances that expose loopback HTTP ports
- attached instances are registered and surfaced in the instance registry, but the normal tab-owner proxy path is not yet equally first-class for them
## Stop Flow
Stopping a managed instance is a server-owned lifecycle operation.
```mermaid
flowchart LR
R["Stop Request"] --> S["Mark stopping"]
S --> G["POST /shutdown to instance"]
G --> W{"Exited?"}
W -->|No| T["SIGTERM"]
T --> K{"Exited?"}
K -->|No| X["SIGKILL"]
W -->|Yes| D["Remove from registry"]
K -->|Yes| D
X --> D
```
Current stop behavior:
- marks the instance as `stopping`
- tries graceful shutdown through the instance HTTP API
- falls back to process-group termination when needed
- releases the allocated port
- removes the instance from the registry and locator cache
For attached instances, there is no child process to kill; the orchestrator only removes its own registration state.
## Instance States
The main statuses surfaced today are:
- `starting`
- `running`
- `stopping`
- `stopped`
- `error`
The orchestrator also emits lifecycle events such as:
- `instance.started`
- `instance.stopped`
- `instance.error`
- `instance.attached`
## Relationship To Other Layers
- **Strategy layer** decides how shorthand requests are exposed or routed in server mode
- **Scheduler** is optional and sits above the same routed execution path
- **Bridge** owns browser state, tab state, and CDP execution
- **Profiles** provide persistent browser data on disk
|