Commit 9ea005a
authored
fix(api): discover the local orchestrator as a template builder (#3386)
## Problem
With `SERVICE_DISCOVERY_PROVIDER=local`, template builds are impossible:
every
build fails with `503 Error when getting available build client`, and
the API
logs
```
WARN No available template builder found with the specified machine info, falling back to any available template builder
ERROR error when getting available build client
failed to get any available template builder for cluster '00000000-0000-0000-0000-000000000000':
available template builder not found
```
The cause is in `handlers/store.go`, in the
`ServiceDiscoveryProviderLocal` branch:
```go
nodeDiscovery = localND
// No template builders in local dev — return an empty list so the
// clusters pool initializes cleanly.
templateBuilderDiscovery = clustersdiscovery.NewStaticDiscovery(nil)
```
`templateBuilderDiscovery` feeds the clusters registry, and
`Cluster.GetAvailableTemplateBuilder` selects from exactly that
registry. With a
permanently empty discovery there is never a candidate, so
`TemplateManager.GetAvailableBuildClient` fails both its primary lookup
and its
"fall back to any builder" retry.
That assumption was correct when the only local orchestrator was the
darwin
dummy (`pkg/dummyserver`), which does not build templates. It is not
correct for
a local orchestrator started with
`ORCHESTRATOR_SERVICES=orchestrator,template-manager`, which is a
supported
configuration and does serve builds.
### Why this is easy to misdiagnose
The 503 is only visible if you are watching the build. `POST
/v3/templates`
succeeds (202) and inserts `env_builds` with `status=waiting` plus the
`env_build_assignments` row for tag `default`; the follow-up
`POST /v2/templates/{id}/builds/{buildID}` is what 503s. The build row
is left
in `waiting` forever.
`GetTemplateWithBuildByTag` requires `env_builds.status_group =
'ready'`, so the
tag lookup returns no rows, and `templateTagNotFoundError` renders as:
```
404: tag 'default' does not exist for template '<team>/base'
```
The tag exists. The build under it is just not `ready`, and never will
be.
`GET /nodes` is also misleading here: it lists orchestrator nodes, which
are
discovered through the separate `nodeDiscovery` path and show up as
`ready`
normally, so the orchestrator looks perfectly healthy while no builder
exists.
## Changes
### 1. Point local template-builder discovery at the local orchestrator
`templateBuilderDiscovery` is now built from
`LOCAL_ORCHESTRATOR_ADDRESS` via a
new `discovery.NewStaticFromAddress`, which parses `host:port` (or bare
`host`,
defaulting to `consts.OrchestratorAPIPort`) and mirrors the
orchestrator-side
`orchestrator/discovery.NewLocal`.
This is self-configuring rather than a new knob: whether the instance is
usable
as a builder is still decided by the roles it reports over the Info RPC
during
instance sync (`Instance.Sync` → `isBuilder`). Concretely:
| local orchestrator | reported roles | `IsBuilder` | builds |
| --- | --- | --- | --- |
| darwin dummy | `[Orchestrator]` | `false` | rejected, as before |
| `ORCHESTRATOR_SERVICES=orchestrator,template-manager` |
`[Orchestrator, TemplateBuilder]` | `true` | works |
So pointing discovery at an orchestrator that does not run
`template-manager` is
harmless — the instance registers with `IsBuilder=false` and
`GetAvailableTemplateBuilder` skips it, which is the current behaviour.
### 2. Do not register local-cluster instances as orchestrator nodes
`connectToClusterNode` now returns early for `consts.LocalClusterID`.
Without this, change 1 introduces a duplicate node. The two registries
identify
the same machine differently:
- node discovery → `nodemanager.New` → `ID: nodeInfo.GetNodeId()`
(self-reported, e.g. `orchestrator-vm`)
- clusters registry → `nodemanager.NewClusterNode` → `ID: i.NodeID`
(discovery item ID, `local`)
`registerNode` keys `o.nodes` by `scopedNodeID(clusterID, nodeID)`, so
an
instance reporting both roles registers twice under two different IDs,
and its
capacity, metrics and sandboxes are counted twice. Observed directly —
`GET /nodes`
returned both `local` and `orchestrator-vm` for a single VM.
Local-cluster orchestrators are owned by the node discovery path; the
local
clusters registry exists only to find template builders. This is already
the
documented intent in `clusters/discovery/local.go`:
> For now, we want to search only for template builders as local
orchestrators
> are still discovered old way via Nomad discovery directly inside node
manager flow.
Nomad and Kubernetes template builders run `template-manager` only and
do not
report the `Orchestrator` role, so `Cluster.GetOrchestrators()` is
already empty
for the local cluster in those setups and the early return is a no-op.
Remote
clusters are unaffected.
## Testing
Verified end to end against a local stack (API + orchestrator with
`ORCHESTRATOR_SERVICES=orchestrator,template-manager`,
`SERVICE_DISCOVERY_PROVIDER=local`):
- before: `POST /v2/templates/{id}/builds/{id}` → 503; build stuck at
`status=waiting`; `e2b sbx cr` → `404: tag 'default' does not exist for
template '<team>/base'`
- after: base template build completes (`status=uploaded`,
`status_group=ready`)
and `e2b sbx cr` starts a sandbox
- after change 2: `GET /nodes` reports one node again instead of two
Added `TestNewStaticFromAddress` covering host:port, bare host
defaulting to
`consts.OrchestratorAPIPort`, IPv6, and the empty-host / bad-port error
paths.
`go test ./packages/api/...` passes (22 packages).1 parent b87ce68 commit 9ea005a
6 files changed
Lines changed: 260 additions & 7 deletions
File tree
- packages/api/internal
- clusters/discovery
- handlers
- orchestrator
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | | - | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
4 | 11 | | |
5 | 12 | | |
6 | 13 | | |
| |||
15 | 22 | | |
16 | 23 | | |
17 | 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 | + | |
18 | 64 | | |
19 | 65 | | |
20 | 66 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 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 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
179 | 179 | | |
180 | 180 | | |
181 | 181 | | |
182 | | - | |
183 | | - | |
184 | | - | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
185 | 192 | | |
186 | 193 | | |
187 | 194 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
43 | 43 | | |
44 | 44 | | |
45 | 45 | | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
46 | 65 | | |
47 | 66 | | |
48 | 67 | | |
49 | 68 | | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
50 | 73 | | |
51 | 74 | | |
52 | 75 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
| 24 | + | |
24 | 25 | | |
25 | 26 | | |
26 | 27 | | |
| |||
336 | 337 | | |
337 | 338 | | |
338 | 339 | | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
67 | 67 | | |
68 | 68 | | |
69 | 69 | | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
70 | 85 | | |
71 | 86 | | |
72 | 87 | | |
| |||
133 | 148 | | |
134 | 149 | | |
135 | 150 | | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
136 | 155 | | |
137 | 156 | | |
138 | 157 | | |
| |||
152 | 171 | | |
153 | 172 | | |
154 | 173 | | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
155 | 178 | | |
156 | 179 | | |
157 | 180 | | |
| |||
180 | 203 | | |
181 | 204 | | |
182 | 205 | | |
183 | | - | |
184 | | - | |
185 | | - | |
186 | 206 | | |
187 | 207 | | |
188 | 208 | | |
| |||
0 commit comments