unitup 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,135 +0,0 @@
1
- ---
2
- name: zero-downtime-deployment
3
- description: >-
4
- Develop, test, and debug zero-downtime deployments, canary releases, rollback sequencing,
5
- generation management, router reverse proxying, connection draining, and readiness probes in Unitup.
6
- Use when modifying core routing, process lifecycle, readiness checks, drain manager, or deploy orchestration.
7
- ---
8
-
9
- # Zero-Downtime Deployment & Traffic Routing in Unitup
10
-
11
- This skill provides architectural guidelines, lifecycle specifications, and testing procedures for Unitup's zero-downtime deployment subsystem.
12
-
13
- ---
14
-
15
- ## 1. Architectural Invariant: Core vs. Deploy Separation
16
-
17
- Unitup strictly decouples low-level process and routing primitives from deployment sequencing:
18
-
19
- ```text
20
- unitup
21
- ├── core/ # Zero-downtime runtime primitives (No deployment sequencing)
22
- │ ├── process-manager.js # Child process lifecycle (start, stop, isAlive, signal, waitForExit)
23
- │ ├── generation-manager.js # Generation records, ephemeral internal ports, disk persistence
24
- │ ├── router.js # HTTP & WebSocket reverse proxy on stable public port, atomic switch, canary weights
25
- │ ├── readiness.js # TCP connect & HTTP 2xx health probes, fast startup failure detection
26
- │ ├── drain-manager.js # In-flight connection tracking, graceful drain, process retirement
27
- │ ├── lock.js # Cross-process deployment concurrency lock
28
- │ ├── supervisor.js # Daemon supervisor (unitupd) managing generations and IPC
29
- │ └── ipc.js # Domain socket / Named Pipe IPC server and client
30
- │
31
- └── deploy/ # Orchestration layer (Composes core primitives)
32
- ├── deployment-manager.js # State machine for full deployments and canary rollouts
33
- └── rollback-manager.js # Rollback sequencing and canary abortion
34
- ```
35
-
36
- ### Golden Rules:
37
- 1. **Never put deployment sequencing into `core/`**: Router, ProcessManager, GenerationManager, and DrainManager must have no knowledge of "steps" or deployment decisions.
38
- 2. **Never put networking or OS primitives into `deploy/`**: DeploymentManager and RollbackManager must only compose core primitives.
39
- 3. **Never build zero-downtime inside CLI commands**: `src/cli.js` must remain a thin adapter that calls `deploy`, `promote`, or `rollback`.
40
- 4. **Never create per-generation OS service units**: Only one supervisor service unit exists per application.
41
-
42
- ---
43
-
44
- ## 2. Deployment State Machine
45
-
46
- DeploymentManager executes a strict, observable state machine:
47
-
48
- ```text
49
- IDLE
50
- └── ACQUIRING_LOCK
51
- └── CREATING_GENERATION
52
- └── STARTING
53
- └── WAITING_READY
54
- ├── (If canary): SETTING_CANARY -> COMPLETE
55
- └── (If full deploy):
56
- SWITCHING
57
- └── STABILIZING
58
- └── DRAINING
59
- └── STOPPING_PREVIOUS
60
- └── COMPLETE
61
- ```
62
-
63
- ### Critical Safety Invariants:
64
- - **Previous Generation Safety**: The previous generation is NEVER stopped or drained until the new generation has passed readiness and traffic has switched.
65
- - **Readiness Failure Preservation**: If the new generation fails readiness or crashes on startup, it is immediately stopped and removed. The router remains pointed at the previous generation, and the deployment fails cleanly.
66
- - **Stabilization Window**: During `stabilizationWindowMs` (default 500ms), if the new generation crashes, traffic is automatically reverted to the previous generation before an error is thrown.
67
- - **Port Mismatch & EADDRINUSE Diagnosis**: If user code hardcodes its listening port instead of reading `process.env.PORT`, `ReadinessChecker` diagnoses this immediately (raising `PortMismatchError` or diagnosing `EADDRINUSE` from captured process stderr) rather than hanging for 15 seconds.
68
-
69
- ---
70
-
71
- ## 3. Canary & Weighted Routing Mechanics
72
-
73
- ### Router Primitives (`src/core/router.js`):
74
- - `setCanary(serviceName, generation, weight)`: Accepts decimal (`0.15`) or percentage (`"15%"` or `15`), normalized to `[0.0, 1.0]`.
75
- - `resolveBackend(serviceName, req)`:
76
- 1. **Header Override**:
77
- - `x-canary: true`, `1`, `always` -> Routes to canary generation deterministically.
78
- - `x-canary: false`, `0`, `never` -> Routes to primary active generation deterministically.
79
- 2. **Probabilistic Splitting**: If `Math.random() < canary.weight`, routes to canary.
80
- 3. **Fallback**: Routes to primary active generation.
81
- - `promoteCanary(serviceName)`: Atomically shifts primary backend to canary, clears canary map, returns promoted generation.
82
- - `clearCanary(serviceName)`: Removes canary backend without touching primary active generation.
83
-
84
- ### Canary Deployment Flow:
85
- ```bash
86
- # 1. Deploy canary with 10% traffic (keeps existing active generation intact)
87
- unitup deploy <app> --canary --weight 10%
88
-
89
- # 2. Inspect status (shows both active and canary generations with port & weight)
90
- unitup status <app>
91
-
92
- # 3A. Promote canary to 100% active (drains and stops old active generation)
93
- unitup promote <app>
94
-
95
- # 3B. OR abort canary (stops and drains canary, keeps old active generation intact)
96
- unitup rollback <app>
97
- ```
98
-
99
- ---
100
-
101
- ## 4. Connection Draining & Streaming Protocols
102
-
103
- [DrainManager](file:///Users/ahmet/projects/unitup/src/core/drain-manager.js) ensures graceful retirement:
104
- 1. `inFlightRequests` map tracks active HTTP requests and WebSocket connections per generation ID.
105
- 2. In `_handleHttpRequest`: increments in-flight counter, decrements on response `'finish'` or `'close'`.
106
- 3. In `_handleWebSocketUpgrade`: increments in-flight counter, decrements on socket `'close'`, `'end'`, or `'error'`.
107
- 4. `DrainManager.drain(generation, { timeout, pollInterval, stopProcess })`:
108
- - Polls `router.getInFlightCount(generation.id)`.
109
- - Waits for active in-flight requests, long-lived WebSockets, Server-Sent Events (SSE), and chunked uploads to complete up to `timeout`.
110
- - Stops the process gracefully (`SIGTERM` -> timeout -> `SIGKILL`).
111
-
112
- ---
113
-
114
- ## 5. Testing & Verification Runbook
115
-
116
- When modifying zero-downtime or routing code, run:
117
-
118
- ```bash
119
- # 1. Core routing and architectural boundary tests
120
- node --test test/router.test.js test/deployment-manager.test.js test/rollback-manager.test.js test/canary.test.js
121
-
122
- # 2. Connection draining & streaming protocols test
123
- node --test test/live-connections.test.js test/drain-manager.test.js
124
-
125
- # 3. Continuous zero-downtime traffic integration test (v1 -> v2 -> v1 -> v2 under load)
126
- node --test test/zero-downtime-integration.test.js
127
-
128
- # 4. Full test suite and type check
129
- npm test
130
- npx tsc --noEmit
131
- ```
132
-
133
- ### Test Construction Rules:
134
- - **Never bind hardcoded ports** like `3000` or `8080`. Always use `port: 0` (ephemeral port allocation) or `findFreePort()` to avoid collisions with running user services.
135
- - **Always clean up servers and sockets** in `afterEach` or `finally` blocks.
package/SECURITY.md DELETED
@@ -1,21 +0,0 @@
1
- # Security Policy
2
-
3
- ## Supported Versions
4
-
5
- Use this section to tell people about which versions of your project are
6
- currently being supported with security updates.
7
-
8
- | Version | Supported |
9
- | ------- | ------------------ |
10
- | 5.1.x | :white_check_mark: |
11
- | 5.0.x | :x: |
12
- | 4.0.x | :white_check_mark: |
13
- | < 4.0 | :x: |
14
-
15
- ## Reporting a Vulnerability
16
-
17
- Use this section to tell people how to report a vulnerability.
18
-
19
- Tell them where to go, how often they can expect to get an update on a
20
- reported vulnerability, what to expect if the vulnerability is accepted or
21
- declined, etc.
package/biome.json DELETED
@@ -1,44 +0,0 @@
1
- {
2
- "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
3
- "vcs": {
4
- "enabled": true,
5
- "clientKind": "git",
6
- "useIgnoreFile": true
7
- },
8
- "files": {
9
- "ignoreUnknown": true,
10
- "ignore": ["node_modules", "dist", "coverage"]
11
- },
12
- "formatter": {
13
- "enabled": true,
14
- "indentStyle": "space",
15
- "indentWidth": 2,
16
- "lineWidth": 120
17
- },
18
- "organizeImports": {
19
- "enabled": true
20
- },
21
- "linter": {
22
- "enabled": true,
23
- "rules": {
24
- "recommended": true,
25
- "style": {
26
- "noUnusedTemplateLiteral": "off"
27
- },
28
- "complexity": {
29
- "noForEach": "off"
30
- },
31
- "suspicious": {
32
- "noEmptyBlockStatements": "off"
33
- }
34
- }
35
- },
36
- "javascript": {
37
- "formatter": {
38
- "quoteStyle": "single",
39
- "jsxQuoteStyle": "double",
40
- "trailingCommas": "none",
41
- "semicolons": "always"
42
- }
43
- }
44
- }