@aristanetworks/eos-mcp-server 0.8.1-beta → 0.9.0-beta
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/CHANGELOG.md +6 -0
- package/README.md +17 -14
- package/dist/commands/probe.js +2 -1
- package/dist/commands/probe.js.map +1 -1
- package/dist/config/diagnostics.d.ts +5 -0
- package/dist/config/diagnostics.js +5 -1
- package/dist/config/diagnostics.js.map +1 -1
- package/dist/config/loadConfig.js +1 -0
- package/dist/config/loadConfig.js.map +1 -1
- package/dist/config/schema.d.ts +95 -1
- package/dist/config/schema.js +14 -1
- package/dist/config/schema.js.map +1 -1
- package/dist/connection/eosDeviceReader.d.ts +6 -1
- package/dist/connection/eosDeviceReader.js +14 -3
- package/dist/connection/eosDeviceReader.js.map +1 -1
- package/dist/diagnostics/executor.d.ts +7 -3
- package/dist/diagnostics/executor.js +16 -13
- package/dist/diagnostics/executor.js.map +1 -1
- package/dist/diagnostics/types.d.ts +19 -2
- package/dist/mcp/createServer.js +20 -3
- package/dist/mcp/createServer.js.map +1 -1
- package/dist/mcp/tools/ping.d.ts +2 -2
- package/dist/operations/eapiSlots.d.ts +68 -0
- package/dist/operations/eapiSlots.js +237 -0
- package/dist/operations/eapiSlots.js.map +1 -0
- package/dist/operations/readExecution.js +1 -1
- package/dist/operations/readExecution.js.map +1 -1
- package/dist/serverInfo/buildServerInfo.js +2 -0
- package/dist/serverInfo/buildServerInfo.js.map +1 -1
- package/dist/serverInfo/types.d.ts +2 -0
- package/docs/CODE_WALKTHROUGH.md +3 -3
- package/docs/DEMO_SKILLS_YOUTUBE.md +346 -0
- package/docs/DESIGN.md +3 -3
- package/docs/DIAGNOSTICS.md +14 -11
- package/docs/adr/0005-multi-destination-ping.md +4 -0
- package/docs/adr/0006-in-memory-timed-diagnostic-capacity.md +2 -0
- package/docs/adr/0007-per-device-diagnostic-concurrency.md +16 -0
- package/docs/adr/0008-read-only-tool-annotations.md +16 -0
- package/docs/adr/0009-shared-per-device-eapi-slots.md +40 -0
- package/docs/research/eos-linter-integration.md +70 -0
- package/package.json +1 -1
- package/dist/diagnostics/concurrency.d.ts +0 -29
- package/dist/diagnostics/concurrency.js +0 -115
- package/dist/diagnostics/concurrency.js.map +0 -1
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Share one per-device eAPI slot budget between reads and diagnostics
|
|
2
|
+
|
|
3
|
+
**Status: accepted.**
|
|
4
|
+
|
|
5
|
+
Extends [ADR 0007](0007-per-device-diagnostic-concurrency.md) from diagnostics to every eAPI request, and closes the read-tool gap that [ADR 0008](0008-read-only-tool-annotations.md) accepted.
|
|
6
|
+
|
|
7
|
+
Since every tool advertises `readOnlyHint`, clients run independent calls at once. Diagnostics are bounded per device across calls, but reads are not: the top-level `deviceConcurrency` (default 5) only limits how many hosts one read call contacts at a time. Measured on 2026-10-29 against cEOS 4.34.3M (node2-1, direct eAPI, 5-packet pings of about 4.2 s):
|
|
8
|
+
|
|
9
|
+
- 3 pings plus 1 `show version`: the show finished at 4.17 s, after the pings; alone it takes about 0.33 s.
|
|
10
|
+
- 2 pings plus 4 shows: all shows finished by 0.38 s.
|
|
11
|
+
- 5 pings: 3 finished at 4.2 s and 2 at 8.3 s.
|
|
12
|
+
|
|
13
|
+
The device runs at most three eAPI requests at a time, shared by pings and reads. Three concurrent 10-packet pings therefore hold every read to that device for about 10 s, the default `readTimeoutMs`, so ping traffic can make show commands time out. A separate read limiter would bound read load but would not stop pings from filling the device.
|
|
14
|
+
|
|
15
|
+
## Decision
|
|
16
|
+
|
|
17
|
+
One admission controller per server process (`src/operations/eapiSlots.ts`, generalizing the ADR 0007 controller) grants **eAPI slots** for every device request, read or diagnostic:
|
|
18
|
+
|
|
19
|
+
- Top-level `deviceConcurrency` (default **3**, was 5) becomes what its name says: the slots one inventory host may hold across all calls, matching the measured cEOS eAPI concurrency.
|
|
20
|
+
- `diagnostics.deviceConcurrency` (default **2**, was 3) caps how many of those slots diagnostics may hold on one host, so a slot stays free for reads. It must not exceed the top-level value; setting them equal accepts that pings may fill a device.
|
|
21
|
+
- `diagnostics.maxConcurrentDiagnostics` (default 32) still caps diagnostics across the process. Reads get no server-wide ceiling.
|
|
22
|
+
- The new top-level `readFanOut` (default 10) caps how many hosts one read call contacts at once, taking over the per-call role the old `deviceConcurrency` had. A 50-host read no longer opens 50 connections at once.
|
|
23
|
+
- `EapiDeviceReader` takes a slot before each request and frees it when the request settles or is aborted, so `readTimeoutMs` starts at dispatch and queue time counts only against `overallOperationTimeoutMs`. Reads do not take ADR 0006's uncertain hold: they are idempotent, bounded by `readTimeoutMs`, and cheap compared with a ping.
|
|
24
|
+
- Waiters are served oldest first, skipping any that cannot run yet. Reads get no priority over diagnostics; the reserved slot already stops pings from filling a device.
|
|
25
|
+
|
|
26
|
+
## Consequences
|
|
27
|
+
|
|
28
|
+
- **Breaking:** top-level `deviceConcurrency` changes meaning from per-call fan-out to per-device slots shared by every call, and its default drops from 5 to 3; per-call fan-out moves to `readFanOut`. `diagnostics.deviceConcurrency` drops from 3 to 2 and must not exceed the top-level value, so a configuration that raised only the diagnostic value must raise both.
|
|
29
|
+
- Pings alone can never fill a device: a read waits only for other reads ahead of it, never for pings. Concurrent pings per device drop from three to two.
|
|
30
|
+
- Many concurrent reads to one device now queue in the server instead of on the device, so a read's `readTimeoutMs` no longer includes time spent behind other requests.
|
|
31
|
+
- The `diagnostics.capacity` snapshot keeps its server-wide diagnostic counts and adds `eapi_device_limit`, plus `read_active_count` and `read_queued_count` for each listed host. Server info adds `limits.read_fan_out`.
|
|
32
|
+
- The `probe` CLI command runs in its own process, so it builds its own slots from the same settings.
|
|
33
|
+
- Other platforms may run more or fewer concurrent eAPI requests; both per-device limits stay configurable.
|
|
34
|
+
|
|
35
|
+
## Alternatives considered
|
|
36
|
+
|
|
37
|
+
- **Separate read limiter per device.** Bounds read load but leaves pings able to fill the device and time out reads.
|
|
38
|
+
- **Only lower `diagnostics.deviceConcurrency` to 2.** Leaves one device slot for reads with no new code, but reads stay unbounded across calls and can still fill the device themselves.
|
|
39
|
+
- **Give reads the uncertain hold.** Adds the lifecycle cost of ADR 0006 for requests that are idempotent and short.
|
|
40
|
+
- **Queue every host of a read call at once, as diagnostics do.** Simpler, but lets one group read open `maxReadTargets` connections at once.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# eos-linter integration assessment
|
|
2
|
+
|
|
3
|
+
Researched 2026-10-21. Recommendation: reuse its **EOS-derived grammar and offline matching approach**, but first obtain an EXEC/show-command schema. Its published configuration schema cannot validate this server's general `show` commands.
|
|
4
|
+
|
|
5
|
+
## Evidence and provenance
|
|
6
|
+
|
|
7
|
+
The requested [GitHub repository](https://github.com/mitchv85/eos-linter) and its API returned 404 through both the connected GitHub tool and anonymous HTTPS. This does not establish whether it is private, moved, or removed. No repository commit or source tree could be verified.
|
|
8
|
+
|
|
9
|
+
Instead, inspected the author's published **0.6.4** extension, published **2026-10-16T13:38:47Z**, using [Open VSX metadata](https://open-vsx.org/api/PacketAnglers/eos-linter/0.6.4), its [manifest](https://open-vsx.org/api/PacketAnglers/eos-linter/0.6.4/file/package.json), [README](https://open-vsx.org/api/PacketAnglers/eos-linter/0.6.4/file/readme.md), [changelog](https://open-vsx.org/api/PacketAnglers/eos-linter/0.6.4/file/changelog.md), and [VSIX](https://open-vsx.org/api/PacketAnglers/eos-linter/0.6.4/file/PacketAnglers.eos-linter-0.6.4.vsix). The archive's calculated SHA-256 matched the [published checksum](https://open-vsx.org/api/PacketAnglers/eos-linter/0.6.4/file/PacketAnglers.eos-linter-0.6.4.sha256): `959ba0c66e3e96e384b2fc00eeef57cc23600e977540e2d49ab60c1ac0e19c89`. No downloaded JavaScript or build/probe scripts were executed.
|
|
10
|
+
|
|
11
|
+
## What is reusable
|
|
12
|
+
|
|
13
|
+
- **TypeScript core.** The manifest's `build:core` bundles `src/core/*.ts` as Node-targeted ESM; the extension bundles `src/extension.ts` as CommonJS, with `vscode` external. No runtime `dependencies` are declared. Development dependencies include TypeScript, esbuild, VS Code types/package tooling and grammar-test libraries. This is compatible in principle with our TypeScript/Node architecture. [Manifest](https://open-vsx.org/api/PacketAnglers/eos-linter/0.6.4/file/package.json)
|
|
14
|
+
- **Grammar rather than command-string lists.** The shipped `out/schema/eos-4.36.2F.json` contains original syntax strings (`s`), compiled expression arrays (`x`), indexes by first keyword, mode transitions, typed placeholders, hidden commands and completion corrections. Example expression tags include sequences (`s`), alternatives (`a`), optional expressions (`o`) and placeholders (`p`). This structure can support both candidate completion and validation. [VSIX, bundled schema](https://open-vsx.org/api/PacketAnglers/eos-linter/0.6.4/file/PacketAnglers.eos-linter-0.6.4.vsix)
|
|
15
|
+
- **Offline validation and completion.** The README describes mode-aware syntax checks, numeric/address/interface types, abbreviations, and next-token completion mirroring EOS `?`; document-defined names improve suggestions. Runtime bundle inspection found only `require("vscode")`, local schema loading and editor providers; no `runCmds`, `getCommandCompletions`, HTTP client or subprocess module. Ordinary linting does not submit candidate commands to a switch. [README](https://open-vsx.org/api/PacketAnglers/eos-linter/0.6.4/file/readme.md), [VSIX](https://open-vsx.org/api/PacketAnglers/eos-linter/0.6.4/file/PacketAnglers.eos-linter-0.6.4.vsix)
|
|
16
|
+
- **Permissive project license.** The packaged MIT license names Copyright 2026 PacketAnglers and requires preservation of its copyright and permission notice when copying substantial portions. [License](https://open-vsx.org/api/PacketAnglers/eos-linter/0.6.4/file/LICENSE.txt)
|
|
17
|
+
|
|
18
|
+
## The critical coverage gap
|
|
19
|
+
|
|
20
|
+
The schema's own `source` metadata states:
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
{
|
|
24
|
+
"version": "4.36.2F-49692818.4362F (engineering build)",
|
|
25
|
+
"command": "show cli commands all-modes | json",
|
|
26
|
+
"capturedUtc": "2026-09-28T19:09:06Z",
|
|
27
|
+
"excluded": [
|
|
28
|
+
"EnableMode",
|
|
29
|
+
"UnprivMode",
|
|
30
|
+
"GlobalConfigModeWithHistory",
|
|
31
|
+
"ConfigSessionMode"
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The hidden-command source uses `show cli commands all-modes hidden | json` with the same exclusions. Neither `EnableMode` nor `UnprivMode` exists in the schema's `modes`. The 72 syntax strings starting with `show` are configuration-context forms such as `show pending`, `show active` and `show diff`, not a general operational-command catalog. **Do not use absence from this schema to reject `show bgp ...` or other EXEC commands.** [VSIX, bundled schema](https://open-vsx.org/api/PacketAnglers/eos-linter/0.6.4/file/PacketAnglers.eos-linter-0.6.4.vsix)
|
|
37
|
+
|
|
38
|
+
The schema reports 769 modes, 6,690 syntax strings, 6,512 compiled entries and **201 truncated entries**, plus 209 compiled hidden entries. It is **2,275,374 bytes**, with additional measured platform/type/reference rules. The README identifies EOS 4.36.2F as its baseline and lists per-release schema selection as future work. Validation is therefore version/platform dependent, with incomplete listing coverage and document-local semantics; a syntactically accepted command does not establish correct troubleshooting intent or authorization. [VSIX](https://open-vsx.org/api/PacketAnglers/eos-linter/0.6.4/file/PacketAnglers.eos-linter-0.6.4.vsix), [README](https://open-vsx.org/api/PacketAnglers/eos-linter/0.6.4/file/readme.md)
|
|
39
|
+
|
|
40
|
+
## Integration shape
|
|
41
|
+
|
|
42
|
+
These are proposed interfaces, not existing eos-linter exports:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
suggestShowCommands({ target, prefix, limit })
|
|
46
|
+
validateShowCommands({ target, commands })
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Expose them as separate read-only MCP tools, backed by a `commandCatalog` module. Suggestions should return short next-token/syntax results with schema release, platform and coverage. Validation should distinguish `valid`, `invalid`, and `unknown`, including incomplete syntax, expected tokens and unsupported schema coverage. For groups, return device-specific compatibility and require every target to pass any configured enforcement rule.
|
|
50
|
+
|
|
51
|
+
Keep three separate decisions: **policy allowed**, **grammar valid**, and **appropriate for the investigation**. Our existing [command guard](../../src/eapi/commands.ts) already enforces single-line `show` input and rejects output modifiers/shell metacharacters. Preserve it before catalog matching and execution. [runShow](../../src/show/runShow.ts) provides the service seam before `reader.runShowCommands`; catalog matches must never authorize configuration or other non-show commands. Initial catalog validation should be advisory while coverage is established. Intent-to-command recommendations still need curated troubleshooting guidance.
|
|
52
|
+
|
|
53
|
+
Prefer extracting or obtaining an upstream library with maintained parser/compiler APIs over importing the VS Code extension. The VSIX exports only `activate` and `deactivate`; core functions are bundled and minified, and its schema loader explicitly requires `GlobalConfigMode` and transitions. The manifest has no library exports, CLI linter or service protocol. Source access is needed to verify separable modules, exact signatures and test contracts before implementation. [Manifest](https://open-vsx.org/api/PacketAnglers/eos-linter/0.6.4/file/package.json), [VSIX](https://open-vsx.org/api/PacketAnglers/eos-linter/0.6.4/file/PacketAnglers.eos-linter-0.6.4.vsix)
|
|
54
|
+
|
|
55
|
+
## Smallest useful experiment
|
|
56
|
+
|
|
57
|
+
1. On a lab device, capture the EXEC/`EnableMode` command listing and confirm it includes representative `show version`, BGP, interfaces and routing syntaxes. Test the trusted discovery command `show cli commands all-modes` using eAPI JSON format, since our public guard rejects `| json`. Listing availability, required privilege and eAPI JSON support remain unverified; the connection attempts below did not return command results.
|
|
58
|
+
2. Extract a bounded show-only catalog; check whether its syntax fits the linter's expression compiler, especially truncated strings, dynamic placeholders and abbreviations. Compare accepted, incomplete and refused examples against that EOS release without automatically executing arbitrary candidates.
|
|
59
|
+
3. Prototype offline prefix completion and advisory validation. Pin schema provenance; key live caches by device/release/platform and credential role, with a TTL. Never return the full catalog through MCP: the existing config schema alone exceeds our default 1 MB response limit. Preserve target resolution, timeouts, limits and `AppError` handling.
|
|
60
|
+
4. Treat config auditing as a separate possible read-only feature using `eos_get_running_config` output. That fits the published schema more directly, but it does not solve operational command discovery and requires full-document/version caveats.
|
|
61
|
+
|
|
62
|
+
Do not implement validation by passing a candidate to eAPI `runCmds`: that executes it. The linter's lab oracle/probe scripts built its evidence; they are not the offline validation runtime and were not available for source review. A community [eAPI tutorial](https://github.com/arista-netdevops-community/arista_eos_automation_with_eAPI#the-getcommandcompletions-method) describes `getCommandCompletions`, but labels those methods informational and advises using only `runCmds`; completion RPC should remain a separate lab investigation, not an assumed supported production API.
|
|
63
|
+
|
|
64
|
+
## Containerlab validation scope
|
|
65
|
+
|
|
66
|
+
The user confirmed that containerized EOS is available for testing and that some commands supported on physical devices may be absent in cEOS. A cEOS-derived catalog must therefore describe its observed platform and release; it cannot be a universal EOS allowlist. Missing catalog entries should produce `unknown` outside that catalog's coverage. A command refused by a cEOS device establishes only that target's observed behavior, not that physical EOS refuses it. Syntax matching also does not establish feature configuration, hardware availability, privileges or JSON output support.
|
|
67
|
+
|
|
68
|
+
Use cEOS for parser/completion integration and supported read-path smoke checks. Keep physical-device command fixtures as separate evidence with release/model provenance, and leave hardware-specific behavior unverified until tested on a suitable device. Distinguish syntax results from operational failures; connectivity or authentication errors provide no evidence about command validity.
|
|
69
|
+
|
|
70
|
+
Local checks on 2026-10-21 found eight running containers using image `ceos-lab:4.34.3M`. The connected MCP inventory's `arista_ceos` group matches their names and management addresses; Docker inspection confirmed `node1-1` at `172.20.20.11` and `node2-1` at `172.20.20.21`. MCP requests for facts and `show cli commands` in JSON format returned `eapi_transport_error` / `EHOSTUNREACH` on these two targets. No command listing or device-reported EOS version was obtained. Connectivity from the MCP server must be established before drawing command-support conclusions. These checks did not change device configuration.
|
package/package.json
CHANGED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import type { DiagnosticCapacitySnapshot, DiagnosticRequest } from "./types.js";
|
|
2
|
-
interface DiagnosticReservationIntent {
|
|
3
|
-
inventoryHostname: string;
|
|
4
|
-
diagnostic: DiagnosticRequest["kind"];
|
|
5
|
-
}
|
|
6
|
-
export interface DiagnosticReservation {
|
|
7
|
-
readonly requestId: string;
|
|
8
|
-
complete(): void;
|
|
9
|
-
markUncertain(reasonCode: string): void;
|
|
10
|
-
}
|
|
11
|
-
/** One instance per server process. A slot with unknown remote completion stays held for the
|
|
12
|
-
* execution budget, then frees itself; a late confirmed response frees it sooner (ADR 0006).
|
|
13
|
-
*/
|
|
14
|
-
export declare class DiagnosticConcurrency {
|
|
15
|
-
private readonly limit;
|
|
16
|
-
private readonly uncertainHoldMs;
|
|
17
|
-
/** Held slots; an uncertain slot carries the timer that frees it. */
|
|
18
|
-
private readonly reservations;
|
|
19
|
-
private readonly waiting;
|
|
20
|
-
private closed;
|
|
21
|
-
constructor(limit: number, uncertainHoldMs: number);
|
|
22
|
-
close(): void;
|
|
23
|
-
snapshot(): DiagnosticCapacitySnapshot;
|
|
24
|
-
acquire(signal: AbortSignal, intent: DiagnosticReservationIntent): Promise<DiagnosticReservation>;
|
|
25
|
-
private reserve;
|
|
26
|
-
private free;
|
|
27
|
-
private markUncertain;
|
|
28
|
-
}
|
|
29
|
-
export {};
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import { randomUUID } from "node:crypto";
|
|
2
|
-
import { AppError } from "../core/errors.js";
|
|
3
|
-
/** One instance per server process. A slot with unknown remote completion stays held for the
|
|
4
|
-
* execution budget, then frees itself; a late confirmed response frees it sooner (ADR 0006).
|
|
5
|
-
*/
|
|
6
|
-
export class DiagnosticConcurrency {
|
|
7
|
-
limit;
|
|
8
|
-
uncertainHoldMs;
|
|
9
|
-
/** Held slots; an uncertain slot carries the timer that frees it. */
|
|
10
|
-
reservations = new Map();
|
|
11
|
-
waiting = [];
|
|
12
|
-
closed = false;
|
|
13
|
-
constructor(limit, uncertainHoldMs) {
|
|
14
|
-
this.limit = limit;
|
|
15
|
-
this.uncertainHoldMs = uncertainHoldMs;
|
|
16
|
-
}
|
|
17
|
-
close() {
|
|
18
|
-
if (this.closed)
|
|
19
|
-
return;
|
|
20
|
-
this.closed = true;
|
|
21
|
-
for (const timer of this.reservations.values())
|
|
22
|
-
clearTimeout(timer);
|
|
23
|
-
const error = closedError();
|
|
24
|
-
for (const waiter of this.waiting.splice(0))
|
|
25
|
-
waiter.reject(error);
|
|
26
|
-
}
|
|
27
|
-
snapshot() {
|
|
28
|
-
const reservations = Array.from(this.reservations.keys(), (reservation) => ({ ...reservation }));
|
|
29
|
-
const uncertain = reservations.filter((reservation) => reservation.state === "uncertain").length;
|
|
30
|
-
return {
|
|
31
|
-
limit: this.limit,
|
|
32
|
-
available_count: this.closed ? 0 : Math.max(0, this.limit - reservations.length),
|
|
33
|
-
active_count: reservations.length - uncertain,
|
|
34
|
-
uncertain_count: uncertain,
|
|
35
|
-
queued_count: this.waiting.length,
|
|
36
|
-
reservations
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
acquire(signal, intent) {
|
|
40
|
-
return new Promise((resolve, reject) => {
|
|
41
|
-
if (signal.aborted) {
|
|
42
|
-
reject(abortedError());
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
if (this.closed) {
|
|
46
|
-
reject(closedError());
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
const cancelled = () => {
|
|
50
|
-
const index = this.waiting.indexOf(waiter);
|
|
51
|
-
if (index >= 0)
|
|
52
|
-
this.waiting.splice(index, 1);
|
|
53
|
-
waiter.reject(abortedError());
|
|
54
|
-
};
|
|
55
|
-
const waiter = {
|
|
56
|
-
reject: (error) => {
|
|
57
|
-
signal.removeEventListener("abort", cancelled);
|
|
58
|
-
reject(error);
|
|
59
|
-
},
|
|
60
|
-
grant: () => {
|
|
61
|
-
signal.removeEventListener("abort", cancelled);
|
|
62
|
-
resolve(this.reserve(intent));
|
|
63
|
-
}
|
|
64
|
-
};
|
|
65
|
-
if (this.reservations.size < this.limit) {
|
|
66
|
-
waiter.grant();
|
|
67
|
-
}
|
|
68
|
-
else {
|
|
69
|
-
this.waiting.push(waiter);
|
|
70
|
-
signal.addEventListener("abort", cancelled, { once: true });
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
reserve(intent) {
|
|
75
|
-
const requestId = randomUUID();
|
|
76
|
-
const state = {
|
|
77
|
-
reservation_id: requestId,
|
|
78
|
-
inventory_hostname: intent.inventoryHostname,
|
|
79
|
-
diagnostic: intent.diagnostic,
|
|
80
|
-
state: "active",
|
|
81
|
-
reserved_at: new Date().toISOString()
|
|
82
|
-
};
|
|
83
|
-
this.reservations.set(state, undefined);
|
|
84
|
-
return {
|
|
85
|
-
requestId,
|
|
86
|
-
complete: () => this.free(state),
|
|
87
|
-
markUncertain: (reasonCode) => this.markUncertain(state, reasonCode)
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
free(state) {
|
|
91
|
-
if (!this.reservations.has(state))
|
|
92
|
-
return;
|
|
93
|
-
clearTimeout(this.reservations.get(state));
|
|
94
|
-
this.reservations.delete(state);
|
|
95
|
-
this.waiting.shift()?.grant();
|
|
96
|
-
}
|
|
97
|
-
markUncertain(state, reasonCode) {
|
|
98
|
-
if (this.closed || !this.reservations.has(state) || state.state === "uncertain")
|
|
99
|
-
return;
|
|
100
|
-
const now = Date.now();
|
|
101
|
-
state.state = "uncertain";
|
|
102
|
-
state.uncertain_since = new Date(now).toISOString();
|
|
103
|
-
state.releases_at = new Date(now + this.uncertainHoldMs).toISOString();
|
|
104
|
-
state.reason_code = reasonCode;
|
|
105
|
-
// Unref so a held slot never keeps a stopping server alive.
|
|
106
|
-
this.reservations.set(state, setTimeout(() => this.free(state), this.uncertainHoldMs).unref());
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
function closedError() {
|
|
110
|
-
return new AppError("diagnostic_server_stopping", "Diagnostic execution is shutting down");
|
|
111
|
-
}
|
|
112
|
-
function abortedError() {
|
|
113
|
-
return new AppError("operation_aborted", "Diagnostic was cancelled while waiting for capacity");
|
|
114
|
-
}
|
|
115
|
-
//# sourceMappingURL=concurrency.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"concurrency.js","sourceRoot":"","sources":["../../src/diagnostics/concurrency.ts"],"names":[],"mappings":"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"}
|