@casys/mcp-server 0.8.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.
- package/mod.ts +161 -0
- package/package.json +32 -0
- package/src/auth/config.ts +229 -0
- package/src/auth/jwt-provider.ts +175 -0
- package/src/auth/middleware.ts +170 -0
- package/src/auth/mod.ts +44 -0
- package/src/auth/presets.ts +129 -0
- package/src/auth/provider.ts +47 -0
- package/src/auth/scope-middleware.ts +59 -0
- package/src/auth/types.ts +69 -0
- package/src/concurrency/rate-limiter.ts +190 -0
- package/src/concurrency/request-queue.ts +140 -0
- package/src/concurrent-server.ts +1899 -0
- package/src/middleware/backpressure.ts +36 -0
- package/src/middleware/mod.ts +21 -0
- package/src/middleware/rate-limit.ts +45 -0
- package/src/middleware/runner.ts +63 -0
- package/src/middleware/types.ts +60 -0
- package/src/middleware/validation.ts +28 -0
- package/src/observability/metrics.ts +378 -0
- package/src/observability/mod.ts +20 -0
- package/src/observability/otel.ts +109 -0
- package/src/runtime/runtime.ts +220 -0
- package/src/runtime/types.ts +90 -0
- package/src/sampling/sampling-bridge.ts +191 -0
- package/src/security/channel-hmac.ts +140 -0
- package/src/security/csp.ts +87 -0
- package/src/security/message-signer.ts +223 -0
- package/src/types.ts +478 -0
- package/src/validation/schema-validator.ts +238 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Request Queue with Concurrency Control and Backpressure
|
|
3
|
+
*
|
|
4
|
+
* Limits the number of concurrent requests to prevent resource exhaustion
|
|
5
|
+
* and implements backpressure strategies when at capacity.
|
|
6
|
+
*
|
|
7
|
+
* @module lib/server/request-queue
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { QueueMetrics, QueueOptions } from "../types.js";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* RequestQueue manages concurrent request execution with backpressure
|
|
14
|
+
*
|
|
15
|
+
* Features:
|
|
16
|
+
* - Limits max concurrent requests (default: 10)
|
|
17
|
+
* - Multiple backpressure strategies: sleep, queue, reject
|
|
18
|
+
* - Metrics for monitoring (inFlight, queued)
|
|
19
|
+
* - Graceful degradation under load
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const queue = new RequestQueue({
|
|
24
|
+
* maxConcurrent: 5,
|
|
25
|
+
* strategy: 'queue',
|
|
26
|
+
* sleepMs: 10
|
|
27
|
+
* });
|
|
28
|
+
*
|
|
29
|
+
* await queue.acquire();
|
|
30
|
+
* try {
|
|
31
|
+
* // Execute request
|
|
32
|
+
* } finally {
|
|
33
|
+
* queue.release();
|
|
34
|
+
* }
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export class RequestQueue {
|
|
38
|
+
private inFlight = 0;
|
|
39
|
+
private maxConcurrent: number;
|
|
40
|
+
private strategy: "sleep" | "queue" | "reject";
|
|
41
|
+
private sleepMs: number;
|
|
42
|
+
private waitQueue: Array<() => void> = [];
|
|
43
|
+
|
|
44
|
+
constructor(options: QueueOptions) {
|
|
45
|
+
this.maxConcurrent = options.maxConcurrent;
|
|
46
|
+
this.strategy = options.strategy;
|
|
47
|
+
this.sleepMs = options.sleepMs;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Acquire a slot for request execution
|
|
52
|
+
* Blocks until a slot is available based on backpressure strategy
|
|
53
|
+
*
|
|
54
|
+
* @throws {Error} If strategy is 'reject' and queue is at capacity
|
|
55
|
+
*/
|
|
56
|
+
async acquire(): Promise<void> {
|
|
57
|
+
if (this.strategy === "reject") {
|
|
58
|
+
// Fail fast - reject immediately if at capacity
|
|
59
|
+
if (this.inFlight >= this.maxConcurrent) {
|
|
60
|
+
throw new Error(
|
|
61
|
+
`Server at capacity (${this.maxConcurrent} concurrent requests)`,
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
this.inFlight++;
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (this.strategy === "queue") {
|
|
69
|
+
// Queue-based backpressure - wait in FIFO queue.
|
|
70
|
+
// Claim the slot BEFORE awaiting to prevent TOCTOU race:
|
|
71
|
+
// without this, two waiters woken back-to-back could both see
|
|
72
|
+
// inFlight < maxConcurrent and both increment past the limit.
|
|
73
|
+
if (this.inFlight >= this.maxConcurrent) {
|
|
74
|
+
await new Promise<void>((resolve) => {
|
|
75
|
+
this.waitQueue.push(resolve);
|
|
76
|
+
});
|
|
77
|
+
// Slot was pre-claimed by release() before waking us
|
|
78
|
+
} else {
|
|
79
|
+
this.inFlight++;
|
|
80
|
+
}
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Sleep-based backpressure (default) - busy-wait with sleep.
|
|
85
|
+
// The check + increment is safe here because JS is single-threaded
|
|
86
|
+
// for synchronous code: after the while loop exits, no other code
|
|
87
|
+
// runs before inFlight++ (no await between check and increment).
|
|
88
|
+
while (this.inFlight >= this.maxConcurrent) {
|
|
89
|
+
await new Promise((resolve) => setTimeout(resolve, this.sleepMs));
|
|
90
|
+
}
|
|
91
|
+
this.inFlight++;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Release a slot after request completion
|
|
96
|
+
* Notifies next waiting request if using queue strategy
|
|
97
|
+
*/
|
|
98
|
+
release(): void {
|
|
99
|
+
if (this.strategy === "queue" && this.waitQueue.length > 0) {
|
|
100
|
+
// Transfer the slot directly to the next waiter without decrementing.
|
|
101
|
+
// This prevents the TOCTOU race: the waiter wakes up with
|
|
102
|
+
// the slot already claimed (inFlight unchanged).
|
|
103
|
+
const next = this.waitQueue.shift()!;
|
|
104
|
+
next();
|
|
105
|
+
} else {
|
|
106
|
+
this.inFlight--;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Get current queue metrics for monitoring
|
|
112
|
+
*/
|
|
113
|
+
getMetrics(): QueueMetrics {
|
|
114
|
+
return {
|
|
115
|
+
inFlight: this.inFlight,
|
|
116
|
+
queued: this.waitQueue.length,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Check if queue is at capacity
|
|
122
|
+
*/
|
|
123
|
+
isAtCapacity(): boolean {
|
|
124
|
+
return this.inFlight >= this.maxConcurrent;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Get current in-flight request count
|
|
129
|
+
*/
|
|
130
|
+
getInFlight(): number {
|
|
131
|
+
return this.inFlight;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Get current queued request count
|
|
136
|
+
*/
|
|
137
|
+
getQueued(): number {
|
|
138
|
+
return this.waitQueue.length;
|
|
139
|
+
}
|
|
140
|
+
}
|