You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/feature_guide/high-scale-provisioning-architecture.md
+35-2Lines changed: 35 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -180,7 +180,38 @@ flowchart TD
180
180
181
181
## 🎯 Intelligent Status Management
182
182
183
-
This state diagram shows the lifecycle of a Node status check. The system **intelligently skips CSP API calls** for Nodes in stable states (Terminated, Failed, Suspended), significantly reducing unnecessary API traffic and improving overall system responsiveness by utilizing cached statuses.
183
+
Status tracking is handled by the **Node Status Agent** (`NodeStatusAgent`), a background daemon that continuously polls CSP Node statuses using a priority-aware scheduler and per-CSP rate limiters — completely decoupled from the API request path.
184
+
185
+
```mermaid
186
+
flowchart LR
187
+
subgraph "Background: NodeStatusAgent"
188
+
TICK[1s tick] --> DISPATCH[Dispatch eligible\nentries from StatusStore]
189
+
DISPATCH --> RATE[Per-CSP rate limiter]
190
+
RATE --> SPIDER[Spider /vmstatus]
191
+
SPIDER --> STORE[StatusStore update]
192
+
end
193
+
194
+
subgraph "API request path (no CSP call)"
195
+
REQ[GET /infra status] --> STORE
196
+
STORE --> RESP[Fresh cached response]
197
+
end
198
+
199
+
style TICK fill:#e3f2fd
200
+
style STORE fill:#fff3e0
201
+
style RESP fill:#4caf50
202
+
```
203
+
204
+
**Poll priorities** drive how often each Node is re-checked:
205
+
206
+
| Priority | Interval | Assigned when |
207
+
|---|---|---|
208
+
|`PollUrgent`|~5 s | Creating, Terminating, Rebooting, … |
209
+
|`PollHigh`|~15 s | Running with pending TargetAction |
210
+
|`PollNormal`|~5 min | Stable Running / Undefined |
211
+
|`PollRecover`|~10 min | Suspended |
212
+
|`PollSkip`| never | Terminated, Failed (final states) |
213
+
214
+
The system also **intelligently skips CSP API calls** for Nodes in final states:
184
215
185
216
```mermaid
186
217
stateDiagram-v2
@@ -209,6 +240,8 @@ stateDiagram-v2
209
240
note right of ParallelProcess : CSP-aware rate<br/>limiting prevents<br/>API throttling
210
241
```
211
242
243
+
> For the full NodeStatusAgent design (StatusStore, operation lock, startup scan, orphan rescue integration), see [Infra Resource Model and Lifecycle Management](./infra-resource-model-and-lifecycle-management.md#node-status-agent).
244
+
212
245
## 🔄 Advanced Caching & Memory Optimization
213
246
214
247
We utilize a **multi-layered caching strategy** for connection configurations and Node statuses. Combined with Go's **channel-based concurrency** and minimal mutex usage, this approach minimizes memory footprint and eliminates redundant network operations, ensuring high performance.
@@ -490,7 +523,7 @@ We have validated the architecture with large-scale provisioning tests. The foll
490
523
491
524
### Performance Improvements
492
525
-**3-Level Rate Limiting**: Prevent API throttling with hierarchical control (CSP → Region → Node).
493
-
-**Smart Status Caching**: Eliminate unnecessary CSP calls for stable Nodes (30-50% call reduction).
526
+
-**Node Status Agent**: Background daemon decouples CSP polling from API requests; priority-aware scheduler (PollUrgent → PollSkip) cuts unnecessary calls by 30–50%.
494
527
-**Parallel Processing**: Optimal performance with unlimited parallelization per CSP and limited parallelization per Region/Node.
@@ -471,28 +471,128 @@ Each Infra and Node maintains two tracking fields:
471
471
472
472
When `TargetStatus == CurrentStatus`, the action is considered complete, and both fields are set to `None` (ActionComplete/StatusComplete).
473
473
474
-
### Smart Status Caching
474
+
### Node Status Agent
475
475
476
-
To optimize performance, the system skips CSP API calls for Nodes in stable final states:
476
+
The **Node Status Agent** (`NodeStatusAgent`) is a background daemon that continuously maintains up-to-date Node status information in memory, decoupling CSP polling from API request handling.
477
+
478
+
#### Why a Background Daemon?
479
+
480
+
Without a daemon, every `GET /infra/{id}` call would fan out to all CSP APIs in real time. For a 200-node multi-cloud Infra, this means 200 concurrent CSP calls per status request — easily triggering rate limits. Under the pull-on-demand model, a live test with 1,061 CSP status calls in 4 minutes was observed before the daemon was introduced.
481
+
482
+
#### Architecture Overview
483
+
484
+
```mermaid
485
+
flowchart TD
486
+
subgraph "NodeStatusAgent (background daemon)"
487
+
TICK[Tick every 1 second] --> DISPATCH[dispatchEligible\nscans StatusStore]
API[GET /infra status] --> CACHE_READ[Read from StatusStore\nor KV]
500
+
end
501
+
502
+
STORE -->|fresh data| CACHE_READ
503
+
504
+
style TICK fill:#e3f2fd
505
+
style STORE fill:#fff3e0
506
+
style CACHE_READ fill:#4caf50
507
+
```
508
+
509
+
#### In-Memory StatusStore
510
+
511
+
The `StatusStore` is a singleton, thread-safe map keyed by `"nsId/infraId/nodeId"`. Each entry holds the most recent CSP-polled status, native status, public IP, and scheduling metadata (next poll time, priority). Status writes go through to the KV store atomically so data survives daemon restarts.
512
+
513
+
#### Poll Priorities
514
+
515
+
Each Node entry in the StatusStore carries a **poll priority** that controls how frequently the daemon re-checks the CSP:
|`PollHigh`|~15 s | Running Nodes with a pending TargetAction |
521
+
|`PollNormal`|~5 min | Stable Running or Undefined nodes (no pending action) |
522
+
|`PollRecover`|~10 min | Suspended nodes (stable, but can be resumed) |
523
+
|`PollSkip`| never | Terminated, Failed nodes (final state — no further CSP calls) |
524
+
525
+
> **Newly created Nodes start at `PollUrgent`** so their transition from Creating → Running is tracked at second-level granularity.
526
+
527
+
#### Operation Lock
528
+
529
+
During active lifecycle operations (Create, Terminate, Reboot, etc.), the daemon must not overwrite the status set by the operation itself. An **operation lock** prevents this:
530
+
531
+
```mermaid
532
+
sequenceDiagram
533
+
participant OPS as Lifecycle goroutine
534
+
participant AGENT as NodeStatusAgent
535
+
participant STORE as StatusStore
536
+
537
+
OPS->>STORE: AcquireLock(nodeId, "Creating")
538
+
Note over STORE: OperationLockedAt = now<br/>TTL = 25 min
539
+
540
+
loop every dispatch tick
541
+
AGENT->>STORE: check lock
542
+
STORE-->>AGENT: locked → skip poll
543
+
end
544
+
545
+
OPS->>STORE: SetStatus("Running")
546
+
OPS->>STORE: ReleaseLock(nodeId)
547
+
548
+
AGENT->>STORE: check lock
549
+
STORE-->>AGENT: unlocked → poll normally
550
+
```
551
+
552
+
If the lock TTL expires while `TargetAction` is still set (e.g. the server crashed mid-operation), the daemon logs a warning, clears the lock, and promotes the Node to `PollUrgent` so the discrepancy is detected quickly. Running `action=reconcile` then corrects the state.
553
+
554
+
#### Startup Scan
555
+
556
+
On daemon start, `StartupScan` reads all Node records from the KV store and populates the StatusStore:
557
+
558
+
- Nodes in **transitional states** (`Creating`, `Terminating`, …) with a **pending `TargetAction`** are promoted to `PollUrgent` and a warning is logged — these likely indicate a server restart mid-operation.
559
+
- Nodes in **stable states** (`Running`, `Suspended`, …) are spread across the first polling interval to avoid a thundering-herd burst on startup.
560
+
- Nodes in **final states** (`Terminated`, `Failed`) are set to `PollSkip` — they require no further CSP calls.
561
+
562
+
#### Smart Status Skipping
563
+
564
+
Before making a CSP API call, `FetchNodeStatus` checks several conditions that allow it to skip the round-trip entirely:
477
565
478
566
```mermaid
479
567
flowchart LR
480
-
CHECK{Node Status?}
481
-
482
-
CHECK -->|Terminated| SKIP[Skip CSP Call]
483
-
CHECK -->|Failed| SKIP
484
-
CHECK -->|Suspended| SKIP
485
-
CHECK -->|Running/Creating| FETCH[Fetch from CSP]
486
-
487
-
SKIP --> CACHE[Return Cached Status]
488
-
FETCH --> UPDATE[Update Cache]
489
-
UPDATE --> RETURN[Return Fresh Status]
490
-
568
+
CHECK{Skip CSP call?}
569
+
570
+
CHECK -->|Terminated\nwith no active action| SKIP[Return cached status]
This optimization reduces API calls by 30-50% for large Infras with many terminated or suspended Nodes.
583
+
This skipping reduces CSP API calls by **30–50%** for large Infras with many terminated or suspended Nodes.
584
+
585
+
#### Relationship to Crash Recovery and Orphan Rescue
586
+
587
+
The NodeStatusAgent tracks status continuously but does **not** attempt to reconcile discrepancies on its own. When a Node ends up `Undefined` (e.g. Spider returned 500 during creation without providing VM identity), the agent simply caches and reports that status. Actual recovery is triggered explicitly:
588
+
589
+
| Mechanism | Who runs it | Purpose |
590
+
|---|---|---|
591
+
|`action=reconcile`| Operator | Re-queries Spider for all transient/Undefined Nodes; queries `/allvm` to find orphan VMs unrecorded in TB; absorbs matched orphans |
592
+
|`action=refine`| Operator | Removes Failed/Undefined Node metadata from TB (no CSP call) |
593
+
|`action=abort`| Operator | Force-terminates all non-final Nodes, runs orphan rescue, then sweeps with refine |
594
+
595
+
See [Crash Recovery](#crash-recovery-reconcile-and-abort) for the full flow.
0 commit comments