@cleocode/cleo 2026.3.4 → 2026.3.6
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.
- package/dist/cli/index.js +2277 -609
- package/dist/cli/index.js.map +4 -4
- package/dist/mcp/index.js +1838 -443
- package/dist/mcp/index.js.map +4 -4
- package/package.json +1 -1
- package/packages/ct-skills/index.js +1 -1
- package/packages/ct-skills/package.json +0 -2
- package/packages/ct-skills/profiles/core.json +1 -1
- package/packages/ct-skills/profiles/full.json +4 -5
- package/packages/ct-skills/profiles/minimal.json +3 -3
- package/packages/ct-skills/profiles/recommended.json +2 -2
- package/packages/ct-skills/provider-skills-map.json +97 -0
- package/packages/ct-skills/skills/_shared/skill-chaining-patterns.md +23 -26
- package/packages/ct-skills/skills/_shared/testing-framework-config.md +9 -9
- package/packages/ct-skills/skills/ct-cleo/SKILL.md +21 -1
- package/packages/ct-skills/skills/ct-dev-workflow/SKILL.md +1 -1
- package/packages/ct-skills/skills/ct-documentor/SKILL.md +1 -1
- package/packages/ct-skills/skills/ct-epic-architect/SKILL.md +1 -1
- package/packages/ct-skills/skills/ct-orchestrator/SKILL.md +119 -43
- package/packages/ct-skills/skills/ct-orchestrator/orchestrator-prompt.txt +17 -0
- package/packages/ct-skills/skills/ct-orchestrator/references/orchestrator-patterns.md +1 -1
- package/packages/ct-skills/skills/ct-research-agent/SKILL.md +1 -1
- package/packages/ct-skills/skills/ct-spec-writer/SKILL.md +1 -1
- package/packages/ct-skills/skills/ct-task-executor/SKILL.md +1 -1
- package/packages/ct-skills/skills/ct-validator/SKILL.md +1 -1
- package/packages/ct-skills/skills/manifest.json +217 -947
- package/packages/ct-skills/skills.json +244 -3
- package/templates/CLEO-INJECTION.md +24 -0
- package/packages/ct-skills/protocols/agent-protocol.md +0 -260
- package/packages/ct-skills/protocols/artifact-publish.md +0 -587
- package/packages/ct-skills/protocols/consensus.md +0 -309
- package/packages/ct-skills/protocols/contribution.md +0 -375
- package/packages/ct-skills/protocols/decomposition.md +0 -352
- package/packages/ct-skills/protocols/implementation.md +0 -344
- package/packages/ct-skills/protocols/provenance.md +0 -600
- package/packages/ct-skills/protocols/release.md +0 -635
- package/packages/ct-skills/protocols/research.md +0 -248
- package/packages/ct-skills/protocols/specification.md +0 -287
- package/packages/ct-skills/protocols/testing.md +0 -346
- package/packages/ct-skills/protocols/validation.md +0 -229
- package/packages/ct-skills/skills/ct-gitbook/SKILL.md +0 -516
- package/packages/ct-skills/skills/ct-gitbook/assets/SUMMARY.md +0 -28
- package/packages/ct-skills/skills/ct-gitbook/assets/gitbook.yaml +0 -14
- package/packages/ct-skills/skills/ct-gitbook/references/api-sdk.md +0 -318
- package/packages/ct-skills/skills/ct-gitbook/references/auth-sso.md +0 -208
- package/packages/ct-skills/skills/ct-gitbook/references/change-requests.md +0 -169
- package/packages/ct-skills/skills/ct-gitbook/references/content-blocks.md +0 -230
- package/packages/ct-skills/skills/ct-gitbook/references/docs-sites.md +0 -202
- package/packages/ct-skills/skills/ct-gitbook/references/git-sync.md +0 -175
- package/packages/ct-skills/skills/ct-gitbook/references/llm-ready.md +0 -178
- package/packages/ct-skills/skills/ct-gitbook/references/migration.md +0 -263
- package/packages/ct-skills/skills/ct-library-implementer-bash/SKILL.md +0 -316
- package/packages/ct-skills/skills/ct-skill-lookup/SKILL.md +0 -179
- package/packages/ct-skills/skills/ct-test-writer-bats/SKILL.md +0 -347
- package/packages/ct-skills/skills/railway-platform/SKILL.md +0 -506
- package/packages/ct-skills/skills/railway-platform/_shared/scripts/railway-api.sh +0 -180
- package/packages/ct-skills/skills/railway-platform/_shared/scripts/railway-common.sh +0 -262
- package/packages/ct-skills/skills/railway-platform/references/01-getting-started.md +0 -149
- package/packages/ct-skills/skills/railway-platform/references/02-projects.md +0 -116
- package/packages/ct-skills/skills/railway-platform/references/03-services.md +0 -147
- package/packages/ct-skills/skills/railway-platform/references/04-deployments.md +0 -210
- package/packages/ct-skills/skills/railway-platform/references/05-databases.md +0 -142
- package/packages/ct-skills/skills/railway-platform/references/06-environments.md +0 -261
- package/packages/ct-skills/skills/railway-platform/references/07-domains.md +0 -139
- package/packages/ct-skills/skills/railway-platform/references/08-volumes.md +0 -533
- package/packages/ct-skills/skills/railway-platform/references/09-networking.md +0 -592
- package/packages/ct-skills/skills/railway-platform/references/10-cron.md +0 -488
- package/packages/ct-skills/skills/railway-platform/references/11-functions.md +0 -170
- package/packages/ct-skills/skills/railway-platform/references/12-monorepo.md +0 -294
- package/packages/ct-skills/skills/railway-platform/references/13-troubleshooting.md +0 -335
- package/packages/ct-skills/skills/railway-platform/references/14-railway-metal.md +0 -197
|
@@ -1,592 +0,0 @@
|
|
|
1
|
-
# Private Networking
|
|
2
|
-
|
|
3
|
-
Railway's private networking enables secure service-to-service communication without exposing traffic to the public internet.
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
**Benefits:**
|
|
8
|
-
- No egress charges for internal traffic
|
|
9
|
-
- Enhanced security (traffic never leaves Railway network)
|
|
10
|
-
- Automatic service discovery
|
|
11
|
-
- Simple hostname-based addressing
|
|
12
|
-
|
|
13
|
-
**Limitations:**
|
|
14
|
-
- Services must be in same project and environment
|
|
15
|
-
- Frontend apps in browser cannot access private network
|
|
16
|
-
- Regional - services in different regions use public networking
|
|
17
|
-
|
|
18
|
-
## How It Works
|
|
19
|
-
|
|
20
|
-
### Private Domains
|
|
21
|
-
|
|
22
|
-
Each service gets a private domain:
|
|
23
|
-
```
|
|
24
|
-
<service-name>.railway.internal
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
**Example:**
|
|
28
|
-
- Service named `api` → `api.railway.internal`
|
|
29
|
-
- Service named `backend` → `backend.railway.internal`
|
|
30
|
-
|
|
31
|
-
### Environment Variables
|
|
32
|
-
|
|
33
|
-
Railway provides these networking variables:
|
|
34
|
-
|
|
35
|
-
| Variable | Value Example | Use Case |
|
|
36
|
-
|----------|---------------|----------|
|
|
37
|
-
| `RAILWAY_PRIVATE_DOMAIN` | `abc123.railway.internal` | Internal addressing |
|
|
38
|
-
| `RAILWAY_PRIVATE_FQDN` | `api.abc123.railway.internal` | Full domain name |
|
|
39
|
-
|
|
40
|
-
## Connecting Services
|
|
41
|
-
|
|
42
|
-
### Backend-to-Backend
|
|
43
|
-
|
|
44
|
-
```
|
|
45
|
-
┌─────────────┐ Private Network ┌─────────────┐
|
|
46
|
-
│ Frontend │ ═══════════════════════► │ API │
|
|
47
|
-
│ (Browser) │ (Not possible) │ (Internal) │
|
|
48
|
-
└─────────────┘ └──────┬──────┘
|
|
49
|
-
│
|
|
50
|
-
│ Private
|
|
51
|
-
│ Network
|
|
52
|
-
▼
|
|
53
|
-
┌─────────────┐
|
|
54
|
-
│ Database │
|
|
55
|
-
│ (Internal) │
|
|
56
|
-
└─────────────┘
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
**Frontend → API:** Must use public domain
|
|
60
|
-
**API → Database:** Uses private networking
|
|
61
|
-
|
|
62
|
-
### Configuration Example
|
|
63
|
-
|
|
64
|
-
```json
|
|
65
|
-
{
|
|
66
|
-
"services": {
|
|
67
|
-
"api": {
|
|
68
|
-
"variables": {
|
|
69
|
-
"DATABASE_URL": {
|
|
70
|
-
"value": "${{Postgres.DATABASE_URL}}"
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
},
|
|
74
|
-
"frontend": {
|
|
75
|
-
"variables": {
|
|
76
|
-
"API_URL": {
|
|
77
|
-
"value": "https://${{API.RAILWAY_PUBLIC_DOMAIN}}"
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
### Service Discovery Pattern
|
|
86
|
-
|
|
87
|
-
```javascript
|
|
88
|
-
// In your application
|
|
89
|
-
const services = {
|
|
90
|
-
api: process.env.API_URL || `http://api.railway.internal`,
|
|
91
|
-
cache: process.env.REDIS_URL || `redis://redis.railway.internal:6379`,
|
|
92
|
-
db: process.env.DATABASE_URL
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
// Make internal request
|
|
96
|
-
const response = await fetch(`${services.api}/internal/health`);
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
## Use Cases
|
|
100
|
-
|
|
101
|
-
### Microservices Architecture
|
|
102
|
-
|
|
103
|
-
```json
|
|
104
|
-
{
|
|
105
|
-
"services": {
|
|
106
|
-
"gateway": {
|
|
107
|
-
"variables": {
|
|
108
|
-
"USERS_SERVICE": {"value": "http://users.railway.internal"},
|
|
109
|
-
"ORDERS_SERVICE": {"value": "http://orders.railway.internal"},
|
|
110
|
-
"INVENTORY_SERVICE": {"value": "http://inventory.railway.internal"}
|
|
111
|
-
}
|
|
112
|
-
},
|
|
113
|
-
"users": {
|
|
114
|
-
"variables": {
|
|
115
|
-
"DATABASE_URL": {"value": "${{UsersDB.DATABASE_URL}}"}
|
|
116
|
-
}
|
|
117
|
-
},
|
|
118
|
-
"orders": {
|
|
119
|
-
"variables": {
|
|
120
|
-
"DATABASE_URL": {"value": "${{OrdersDB.DATABASE_URL}}"},
|
|
121
|
-
"USERS_API": {"value": "http://users.railway.internal"}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
### API + Worker Pattern
|
|
129
|
-
|
|
130
|
-
```json
|
|
131
|
-
{
|
|
132
|
-
"services": {
|
|
133
|
-
"api": {
|
|
134
|
-
"variables": {
|
|
135
|
-
"REDIS_URL": {"value": "${{Redis.REDIS_URL}}"},
|
|
136
|
-
"DATABASE_URL": {"value": "${{Postgres.DATABASE_URL}}"}
|
|
137
|
-
}
|
|
138
|
-
},
|
|
139
|
-
"worker": {
|
|
140
|
-
"variables": {
|
|
141
|
-
"REDIS_URL": {"value": "${{Redis.REDIS_URL}}"},
|
|
142
|
-
"DATABASE_URL": {"value": "${{Postgres.DATABASE_URL}}"},
|
|
143
|
-
"API_URL": {"value": "http://api.railway.internal"}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
**Worker fetches jobs from Redis, calls API for processing:**
|
|
151
|
-
```javascript
|
|
152
|
-
// worker.js
|
|
153
|
-
const Queue = require('bull');
|
|
154
|
-
const queue = new Queue('jobs', process.env.REDIS_URL);
|
|
155
|
-
|
|
156
|
-
queue.process(async (job) => {
|
|
157
|
-
// Call API for processing
|
|
158
|
-
const response = await fetch(`${process.env.API_URL}/process`, {
|
|
159
|
-
method: 'POST',
|
|
160
|
-
body: JSON.stringify(job.data)
|
|
161
|
-
});
|
|
162
|
-
return response.json();
|
|
163
|
-
});
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
## TCP Proxy
|
|
167
|
-
|
|
168
|
-
For external access to internal services:
|
|
169
|
-
|
|
170
|
-
### Enable TCP Proxy
|
|
171
|
-
|
|
172
|
-
```json
|
|
173
|
-
{
|
|
174
|
-
"services": {
|
|
175
|
-
"postgres": {
|
|
176
|
-
"networking": {
|
|
177
|
-
"tcpProxy": {
|
|
178
|
-
"enabled": true,
|
|
179
|
-
"port": 5432
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
### Connection URL
|
|
188
|
-
|
|
189
|
-
With TCP proxy enabled:
|
|
190
|
-
```
|
|
191
|
-
${{Postgres.DATABASE_PUBLIC_URL}}
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
**Warning:** TCP proxy exposes service to internet. Use strong authentication.
|
|
195
|
-
|
|
196
|
-
## Networking Architecture
|
|
197
|
-
|
|
198
|
-
### Regional Networking
|
|
199
|
-
|
|
200
|
-
Services in same region:
|
|
201
|
-
```
|
|
202
|
-
┌──────────────┐ ┌──────────────┐
|
|
203
|
-
│ Service A │◄───────►│ Service B │
|
|
204
|
-
│ us-west1 │ Private │ us-west1 │
|
|
205
|
-
└──────────────┘ └──────────────┘
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
Services in different regions:
|
|
209
|
-
```
|
|
210
|
-
┌──────────────┐ Public ┌──────────────┐
|
|
211
|
-
│ Service A │◄──────────────────────►│ Service B │
|
|
212
|
-
│ us-west1 │ (Egress charges) │ us-east1 │
|
|
213
|
-
└──────────────┘ └──────────────┘
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
**Best practice:** Deploy related services to same region for free internal networking.
|
|
217
|
-
|
|
218
|
-
### Railway Metal Networking
|
|
219
|
-
|
|
220
|
-
Railway Metal uses enhanced networking:
|
|
221
|
-
- Anycast edge network
|
|
222
|
-
- Optimized routing
|
|
223
|
-
- Lower latency
|
|
224
|
-
|
|
225
|
-
Services on Railway Metal in same region still use private networking.
|
|
226
|
-
|
|
227
|
-
## Security
|
|
228
|
-
|
|
229
|
-
### Private Network Isolation
|
|
230
|
-
|
|
231
|
-
Traffic within private network:
|
|
232
|
-
- ✅ Encrypted in transit
|
|
233
|
-
- ✅ Isolated from other projects
|
|
234
|
-
- ✅ Not exposed to internet
|
|
235
|
-
- ✅ No egress charges
|
|
236
|
-
|
|
237
|
-
### Frontend Considerations
|
|
238
|
-
|
|
239
|
-
**Never expose private domains to frontend:**
|
|
240
|
-
|
|
241
|
-
**Bad (frontend code):**
|
|
242
|
-
```javascript
|
|
243
|
-
// This won't work - browser can't access private network
|
|
244
|
-
const apiUrl = 'http://api.railway.internal';
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
**Good (frontend code):**
|
|
248
|
-
```javascript
|
|
249
|
-
// Use public domain
|
|
250
|
-
const apiUrl = 'https://api.up.railway.app';
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
### Database Security
|
|
254
|
-
|
|
255
|
-
**Recommended:**
|
|
256
|
-
```json
|
|
257
|
-
{
|
|
258
|
-
"services": {
|
|
259
|
-
"database": {
|
|
260
|
-
"networking": {
|
|
261
|
-
"tcpProxy": {
|
|
262
|
-
"enabled": false // Keep private
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
```
|
|
269
|
-
|
|
270
|
-
Only enable TCP proxy when external access is absolutely required.
|
|
271
|
-
|
|
272
|
-
## Troubleshooting
|
|
273
|
-
|
|
274
|
-
### Cannot Connect to Private Domain
|
|
275
|
-
|
|
276
|
-
**Symptoms:**
|
|
277
|
-
- `connection refused`
|
|
278
|
-
- `getaddrinfo ENOTFOUND`
|
|
279
|
-
- Timeout errors
|
|
280
|
-
|
|
281
|
-
**Checklist:**
|
|
282
|
-
|
|
283
|
-
1. **Same project and environment:**
|
|
284
|
-
```bash
|
|
285
|
-
railway status --json
|
|
286
|
-
# Verify both services show same project and environment
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
2. **Service is deployed:**
|
|
290
|
-
```bash
|
|
291
|
-
railway service status --json
|
|
292
|
-
# Check deployment status is SUCCESS
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
3. **Correct domain format:**
|
|
296
|
-
```
|
|
297
|
-
# Good
|
|
298
|
-
http://api.railway.internal
|
|
299
|
-
|
|
300
|
-
# Bad (missing protocol)
|
|
301
|
-
api.railway.internal
|
|
302
|
-
|
|
303
|
-
# Bad (wrong suffix)
|
|
304
|
-
api.railway.app
|
|
305
|
-
```
|
|
306
|
-
|
|
307
|
-
4. **Port is correct:**
|
|
308
|
-
```
|
|
309
|
-
# HTTP services
|
|
310
|
-
http://api.railway.internal:8080
|
|
311
|
-
|
|
312
|
-
# Default HTTP port (80) not used internally
|
|
313
|
-
```
|
|
314
|
-
|
|
315
|
-
### Connection Timeout
|
|
316
|
-
|
|
317
|
-
**Causes:**
|
|
318
|
-
- Service crashed
|
|
319
|
-
- Service not listening on correct port
|
|
320
|
-
- Health check failing
|
|
321
|
-
|
|
322
|
-
**Debug:**
|
|
323
|
-
```bash
|
|
324
|
-
# Check service health
|
|
325
|
-
railway service status
|
|
326
|
-
|
|
327
|
-
# View logs
|
|
328
|
-
railway logs --lines 100
|
|
329
|
-
|
|
330
|
-
# SSH to debug
|
|
331
|
-
railway ssh
|
|
332
|
-
```
|
|
333
|
-
|
|
334
|
-
### Cross-Region Issues
|
|
335
|
-
|
|
336
|
-
**Symptom:** High latency or connection issues between services
|
|
337
|
-
|
|
338
|
-
**Cause:** Services in different regions use public networking
|
|
339
|
-
|
|
340
|
-
**Solutions:**
|
|
341
|
-
1. Deploy services to same region
|
|
342
|
-
2. Accept latency/cost trade-off
|
|
343
|
-
3. Use CDN for static assets
|
|
344
|
-
|
|
345
|
-
### DNS Resolution Failures
|
|
346
|
-
|
|
347
|
-
**Test DNS:**
|
|
348
|
-
```bash
|
|
349
|
-
# From within container
|
|
350
|
-
railway ssh
|
|
351
|
-
|
|
352
|
-
# Check resolution
|
|
353
|
-
nslookup api.railway.internal
|
|
354
|
-
dig api.railway.internal
|
|
355
|
-
```
|
|
356
|
-
|
|
357
|
-
## Best Practices
|
|
358
|
-
|
|
359
|
-
### 1. Use Environment Variables
|
|
360
|
-
|
|
361
|
-
Don't hardcode private domains:
|
|
362
|
-
|
|
363
|
-
**Good:**
|
|
364
|
-
```javascript
|
|
365
|
-
const apiUrl = process.env.API_URL || 'http://api.railway.internal';
|
|
366
|
-
```
|
|
367
|
-
|
|
368
|
-
**Bad:**
|
|
369
|
-
```javascript
|
|
370
|
-
const apiUrl = 'http://api.railway.internal'; // Hardcoded
|
|
371
|
-
```
|
|
372
|
-
|
|
373
|
-
### 2. Health Checks for Dependencies
|
|
374
|
-
|
|
375
|
-
Verify connections at startup:
|
|
376
|
-
|
|
377
|
-
```javascript
|
|
378
|
-
async function checkDependencies() {
|
|
379
|
-
const deps = [
|
|
380
|
-
{ name: 'API', url: process.env.API_URL + '/health' },
|
|
381
|
-
{ name: 'Redis', url: process.env.REDIS_URL }
|
|
382
|
-
];
|
|
383
|
-
|
|
384
|
-
for (const dep of deps) {
|
|
385
|
-
try {
|
|
386
|
-
await fetch(dep.url);
|
|
387
|
-
console.log(`✓ ${dep.name} is reachable`);
|
|
388
|
-
} catch (error) {
|
|
389
|
-
console.error(`✗ ${dep.name} is not reachable:`, error.message);
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
```
|
|
394
|
-
|
|
395
|
-
### 3. Retry Logic
|
|
396
|
-
|
|
397
|
-
Handle transient network issues:
|
|
398
|
-
|
|
399
|
-
```javascript
|
|
400
|
-
async function fetchWithRetry(url, options = {}, maxRetries = 3) {
|
|
401
|
-
for (let i = 0; i < maxRetries; i++) {
|
|
402
|
-
try {
|
|
403
|
-
const response = await fetch(url, options);
|
|
404
|
-
if (response.ok) return response;
|
|
405
|
-
} catch (error) {
|
|
406
|
-
if (i === maxRetries - 1) throw error;
|
|
407
|
-
await new Promise(r => setTimeout(r, 1000 * (i + 1)));
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
```
|
|
412
|
-
|
|
413
|
-
### 4. Circuit Breaker Pattern
|
|
414
|
-
|
|
415
|
-
Prevent cascading failures:
|
|
416
|
-
|
|
417
|
-
```javascript
|
|
418
|
-
class CircuitBreaker {
|
|
419
|
-
constructor(threshold = 5, timeout = 60000) {
|
|
420
|
-
this.failureCount = 0;
|
|
421
|
-
this.threshold = threshold;
|
|
422
|
-
this.timeout = timeout;
|
|
423
|
-
this.state = 'CLOSED';
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
async call(fn) {
|
|
427
|
-
if (this.state === 'OPEN') {
|
|
428
|
-
throw new Error('Circuit breaker is OPEN');
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
try {
|
|
432
|
-
const result = await fn();
|
|
433
|
-
this.success();
|
|
434
|
-
return result;
|
|
435
|
-
} catch (error) {
|
|
436
|
-
this.failure();
|
|
437
|
-
throw error;
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
success() {
|
|
442
|
-
this.failureCount = 0;
|
|
443
|
-
this.state = 'CLOSED';
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
failure() {
|
|
447
|
-
this.failureCount++;
|
|
448
|
-
if (this.failureCount >= this.threshold) {
|
|
449
|
-
this.state = 'OPEN';
|
|
450
|
-
setTimeout(() => {
|
|
451
|
-
this.state = 'HALF_OPEN';
|
|
452
|
-
}, this.timeout);
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
```
|
|
457
|
-
|
|
458
|
-
### 5. Regional Co-location
|
|
459
|
-
|
|
460
|
-
Deploy related services to same region:
|
|
461
|
-
|
|
462
|
-
```json
|
|
463
|
-
{
|
|
464
|
-
"services": {
|
|
465
|
-
"api": {
|
|
466
|
-
"deploy": {
|
|
467
|
-
"multiRegionConfig": {
|
|
468
|
-
"us-west1": {"numReplicas": 2},
|
|
469
|
-
"us-east1": {"numReplicas": 2}
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
},
|
|
473
|
-
"database": {
|
|
474
|
-
"deploy": {
|
|
475
|
-
"multiRegionConfig": {
|
|
476
|
-
"us-west1": {"numReplicas": 1}
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
```
|
|
483
|
-
|
|
484
|
-
## Examples
|
|
485
|
-
|
|
486
|
-
### Complete Microservices Setup
|
|
487
|
-
|
|
488
|
-
```json
|
|
489
|
-
{
|
|
490
|
-
"services": {
|
|
491
|
-
"gateway": {
|
|
492
|
-
"variables": {
|
|
493
|
-
"AUTH_SERVICE": {"value": "http://auth.railway.internal:8080"},
|
|
494
|
-
"USER_SERVICE": {"value": "http://users.railway.internal:8080"},
|
|
495
|
-
"ORDER_SERVICE": {"value": "http://orders.railway.internal:8080"}
|
|
496
|
-
}
|
|
497
|
-
},
|
|
498
|
-
"auth": {
|
|
499
|
-
"variables": {
|
|
500
|
-
"DATABASE_URL": {"value": "${{AuthDB.DATABASE_URL}}"},
|
|
501
|
-
"REDIS_URL": {"value": "${{Redis.REDIS_URL}}"}
|
|
502
|
-
}
|
|
503
|
-
},
|
|
504
|
-
"users": {
|
|
505
|
-
"variables": {
|
|
506
|
-
"DATABASE_URL": {"value": "${{UsersDB.DATABASE_URL}}"},
|
|
507
|
-
"AUTH_URL": {"value": "http://auth.railway.internal:8080"}
|
|
508
|
-
}
|
|
509
|
-
},
|
|
510
|
-
"orders": {
|
|
511
|
-
"variables": {
|
|
512
|
-
"DATABASE_URL": {"value": "${{OrdersDB.DATABASE_URL}}"},
|
|
513
|
-
"USER_SERVICE": {"value": "http://users.railway.internal:8080"},
|
|
514
|
-
"INVENTORY_SERVICE": {"value": "http://inventory.railway.internal:8080"}
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
```
|
|
520
|
-
|
|
521
|
-
**Gateway routing:**
|
|
522
|
-
```javascript
|
|
523
|
-
// gateway/index.js
|
|
524
|
-
const express = require('express');
|
|
525
|
-
const proxy = require('http-proxy-middleware');
|
|
526
|
-
|
|
527
|
-
const app = express();
|
|
528
|
-
|
|
529
|
-
app.use('/auth', proxy({
|
|
530
|
-
target: process.env.AUTH_SERVICE,
|
|
531
|
-
changeOrigin: true
|
|
532
|
-
}));
|
|
533
|
-
|
|
534
|
-
app.use('/users', proxy({
|
|
535
|
-
target: process.env.USER_SERVICE,
|
|
536
|
-
changeOrigin: true
|
|
537
|
-
}));
|
|
538
|
-
|
|
539
|
-
app.use('/orders', proxy({
|
|
540
|
-
target: process.env.ORDER_SERVICE,
|
|
541
|
-
changeOrigin: true
|
|
542
|
-
}));
|
|
543
|
-
|
|
544
|
-
app.listen(process.env.PORT);
|
|
545
|
-
```
|
|
546
|
-
|
|
547
|
-
### Worker Queue Pattern
|
|
548
|
-
|
|
549
|
-
```javascript
|
|
550
|
-
// worker.js
|
|
551
|
-
const Queue = require('bull');
|
|
552
|
-
const axios = require('axios');
|
|
553
|
-
|
|
554
|
-
const taskQueue = new Queue('tasks', process.env.REDIS_URL);
|
|
555
|
-
|
|
556
|
-
const apiClient = axios.create({
|
|
557
|
-
baseURL: process.env.API_URL
|
|
558
|
-
});
|
|
559
|
-
|
|
560
|
-
taskQueue.process(async (job) => {
|
|
561
|
-
console.log(`Processing job ${job.id}:`, job.data);
|
|
562
|
-
|
|
563
|
-
// Fetch additional data from API
|
|
564
|
-
const user = await apiClient.get(`/users/${job.data.userId}`);
|
|
565
|
-
|
|
566
|
-
// Process task
|
|
567
|
-
const result = await processTask(job.data, user.data);
|
|
568
|
-
|
|
569
|
-
// Report completion
|
|
570
|
-
await apiClient.post(`/jobs/${job.id}/complete`, result);
|
|
571
|
-
|
|
572
|
-
return result;
|
|
573
|
-
});
|
|
574
|
-
|
|
575
|
-
async function processTask(data, user) {
|
|
576
|
-
// Task processing logic
|
|
577
|
-
return { success: true, processedAt: new Date() };
|
|
578
|
-
}
|
|
579
|
-
```
|
|
580
|
-
|
|
581
|
-
## Summary
|
|
582
|
-
|
|
583
|
-
| Feature | Details |
|
|
584
|
-
|---------|---------|
|
|
585
|
-
| **Domain format** | `service-name.railway.internal` |
|
|
586
|
-
| **Cost** | Free (no egress charges) |
|
|
587
|
-
| **Scope** | Same project and environment |
|
|
588
|
-
| **Security** | Encrypted, isolated from internet |
|
|
589
|
-
| **Discovery** | Automatic via service name |
|
|
590
|
-
| **Regions** | Same region only for private |
|
|
591
|
-
|
|
592
|
-
**Key rule:** Private networking is for backend-to-backend only. Frontends must use public domains.
|