@elaraai/e3-rack 0.0.0-bootstrap.0 → 1.0.94
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/README.md +407 -2
- package/dist/src/client/client.spec.d.ts +6 -0
- package/dist/src/client/client.spec.d.ts.map +1 -0
- package/dist/src/client/client.spec.js +150 -0
- package/dist/src/client/client.spec.js.map +1 -0
- package/dist/src/client/connect.d.ts +52 -0
- package/dist/src/client/connect.d.ts.map +1 -0
- package/dist/src/client/connect.js +112 -0
- package/dist/src/client/connect.js.map +1 -0
- package/dist/src/client/hub-client.d.ts +57 -0
- package/dist/src/client/hub-client.d.ts.map +1 -0
- package/dist/src/client/hub-client.js +87 -0
- package/dist/src/client/hub-client.js.map +1 -0
- package/dist/src/client/local-http.d.ts +78 -0
- package/dist/src/client/local-http.d.ts.map +1 -0
- package/dist/src/client/local-http.js +149 -0
- package/dist/src/client/local-http.js.map +1 -0
- package/dist/src/client/session-attempts.d.ts +20 -0
- package/dist/src/client/session-attempts.d.ts.map +1 -0
- package/dist/src/client/session-attempts.js +88 -0
- package/dist/src/client/session-attempts.js.map +1 -0
- package/dist/src/client/session-data-server.d.ts +37 -0
- package/dist/src/client/session-data-server.d.ts.map +1 -0
- package/dist/src/client/session-data-server.js +280 -0
- package/dist/src/client/session-data-server.js.map +1 -0
- package/dist/src/client/session-data-server.spec.d.ts +6 -0
- package/dist/src/client/session-data-server.spec.d.ts.map +1 -0
- package/dist/src/client/session-data-server.spec.js +192 -0
- package/dist/src/client/session-data-server.spec.js.map +1 -0
- package/dist/src/client/session.d.ts +119 -0
- package/dist/src/client/session.d.ts.map +1 -0
- package/dist/src/client/session.js +290 -0
- package/dist/src/client/session.js.map +1 -0
- package/dist/src/hub/config.d.ts +74 -0
- package/dist/src/hub/config.d.ts.map +1 -0
- package/dist/src/hub/config.js +159 -0
- package/dist/src/hub/config.js.map +1 -0
- package/dist/src/hub/fair-lease-store.d.ts +36 -0
- package/dist/src/hub/fair-lease-store.d.ts.map +1 -0
- package/dist/src/hub/fair-lease-store.js +73 -0
- package/dist/src/hub/fair-lease-store.js.map +1 -0
- package/dist/src/hub/hub.d.ts +91 -0
- package/dist/src/hub/hub.d.ts.map +1 -0
- package/dist/src/hub/hub.js +641 -0
- package/dist/src/hub/hub.js.map +1 -0
- package/dist/src/hub/hub.spec.d.ts +6 -0
- package/dist/src/hub/hub.spec.d.ts.map +1 -0
- package/dist/src/hub/hub.spec.js +363 -0
- package/dist/src/hub/hub.spec.js.map +1 -0
- package/dist/src/hub/infrastructure.spec.d.ts +6 -0
- package/dist/src/hub/infrastructure.spec.d.ts.map +1 -0
- package/dist/src/hub/infrastructure.spec.js +211 -0
- package/dist/src/hub/infrastructure.spec.js.map +1 -0
- package/dist/src/hub/lock.d.ts +62 -0
- package/dist/src/hub/lock.d.ts.map +1 -0
- package/dist/src/hub/lock.js +165 -0
- package/dist/src/hub/lock.js.map +1 -0
- package/dist/src/hub/main.d.ts +16 -0
- package/dist/src/hub/main.d.ts.map +1 -0
- package/dist/src/hub/main.js +56 -0
- package/dist/src/hub/main.js.map +1 -0
- package/dist/src/hub/session-bridge.d.ts +116 -0
- package/dist/src/hub/session-bridge.d.ts.map +1 -0
- package/dist/src/hub/session-bridge.js +336 -0
- package/dist/src/hub/session-bridge.js.map +1 -0
- package/dist/src/identity/file-identity-store.d.ts +18 -0
- package/dist/src/identity/file-identity-store.d.ts.map +1 -0
- package/dist/src/identity/file-identity-store.js +34 -0
- package/dist/src/identity/file-identity-store.js.map +1 -0
- package/dist/src/identity/file-identity-store.spec.d.ts +6 -0
- package/dist/src/identity/file-identity-store.spec.d.ts.map +1 -0
- package/dist/src/identity/file-identity-store.spec.js +59 -0
- package/dist/src/identity/file-identity-store.spec.js.map +1 -0
- package/dist/src/identity/in-memory-identity-store.d.ts +48 -0
- package/dist/src/identity/in-memory-identity-store.d.ts.map +1 -0
- package/dist/src/identity/in-memory-identity-store.js +102 -0
- package/dist/src/identity/in-memory-identity-store.js.map +1 -0
- package/dist/src/identity/machine-identity.d.ts +134 -0
- package/dist/src/identity/machine-identity.d.ts.map +1 -0
- package/dist/src/identity/machine-identity.js +65 -0
- package/dist/src/identity/machine-identity.js.map +1 -0
- package/dist/src/index.d.ts +34 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +34 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/lease/closure.d.ts +96 -0
- package/dist/src/lease/closure.d.ts.map +1 -0
- package/dist/src/lease/closure.js +192 -0
- package/dist/src/lease/closure.js.map +1 -0
- package/dist/src/lease/closure.spec.d.ts +6 -0
- package/dist/src/lease/closure.spec.d.ts.map +1 -0
- package/dist/src/lease/closure.spec.js +35 -0
- package/dist/src/lease/closure.spec.js.map +1 -0
- package/dist/src/lease/coordinator.d.ts +34 -0
- package/dist/src/lease/coordinator.d.ts.map +1 -0
- package/dist/src/lease/coordinator.js +42 -0
- package/dist/src/lease/coordinator.js.map +1 -0
- package/dist/src/lease/in-memory-lease-store.d.ts +58 -0
- package/dist/src/lease/in-memory-lease-store.d.ts.map +1 -0
- package/dist/src/lease/in-memory-lease-store.js +132 -0
- package/dist/src/lease/in-memory-lease-store.js.map +1 -0
- package/dist/src/lease/lease-store.d.ts +169 -0
- package/dist/src/lease/lease-store.d.ts.map +1 -0
- package/dist/src/lease/lease-store.js +94 -0
- package/dist/src/lease/lease-store.js.map +1 -0
- package/dist/src/lease/lease-store.spec.d.ts +6 -0
- package/dist/src/lease/lease-store.spec.d.ts.map +1 -0
- package/dist/src/lease/lease-store.spec.js +8 -0
- package/dist/src/lease/lease-store.spec.js.map +1 -0
- package/dist/src/lease/rack-dispatch.d.ts +105 -0
- package/dist/src/lease/rack-dispatch.d.ts.map +1 -0
- package/dist/src/lease/rack-dispatch.js +6 -0
- package/dist/src/lease/rack-dispatch.js.map +1 -0
- package/dist/src/mutation-queue.d.ts +13 -0
- package/dist/src/mutation-queue.d.ts.map +1 -0
- package/dist/src/mutation-queue.js +17 -0
- package/dist/src/mutation-queue.js.map +1 -0
- package/dist/src/paths.d.ts +56 -0
- package/dist/src/paths.d.ts.map +1 -0
- package/dist/src/paths.js +82 -0
- package/dist/src/paths.js.map +1 -0
- package/dist/src/protocol/control.d.ts +295 -0
- package/dist/src/protocol/control.d.ts.map +1 -0
- package/dist/src/protocol/control.js +74 -0
- package/dist/src/protocol/control.js.map +1 -0
- package/dist/src/protocol/index.d.ts +9 -0
- package/dist/src/protocol/index.d.ts.map +1 -0
- package/dist/src/protocol/index.js +9 -0
- package/dist/src/protocol/index.js.map +1 -0
- package/dist/src/protocol/rack-wire.d.ts +357 -0
- package/dist/src/protocol/rack-wire.d.ts.map +1 -0
- package/dist/src/protocol/rack-wire.js +262 -0
- package/dist/src/protocol/rack-wire.js.map +1 -0
- package/dist/src/protocol/rack-wire.spec.d.ts +6 -0
- package/dist/src/protocol/rack-wire.spec.d.ts.map +1 -0
- package/dist/src/protocol/rack-wire.spec.js +14 -0
- package/dist/src/protocol/rack-wire.spec.js.map +1 -0
- package/dist/src/protocol/registration.d.ts +70 -0
- package/dist/src/protocol/registration.d.ts.map +1 -0
- package/dist/src/protocol/registration.js +67 -0
- package/dist/src/protocol/registration.js.map +1 -0
- package/dist/src/protocol/session-data.d.ts +69 -0
- package/dist/src/protocol/session-data.d.ts.map +1 -0
- package/dist/src/protocol/session-data.js +26 -0
- package/dist/src/protocol/session-data.js.map +1 -0
- package/dist/src/protocol/task-envelope.d.ts +198 -0
- package/dist/src/protocol/task-envelope.d.ts.map +1 -0
- package/dist/src/protocol/task-envelope.js +93 -0
- package/dist/src/protocol/task-envelope.js.map +1 -0
- package/dist/src/protocol/wire-golden.d.ts +8 -0
- package/dist/src/protocol/wire-golden.d.ts.map +1 -0
- package/dist/src/protocol/wire-golden.js +34 -0
- package/dist/src/protocol/wire-golden.js.map +1 -0
- package/dist/src/protocol/wire-samples.d.ts +11 -0
- package/dist/src/protocol/wire-samples.d.ts.map +1 -0
- package/dist/src/protocol/wire-samples.js +52 -0
- package/dist/src/protocol/wire-samples.js.map +1 -0
- package/dist/src/registry/file-rack-registry.d.ts +68 -0
- package/dist/src/registry/file-rack-registry.d.ts.map +1 -0
- package/dist/src/registry/file-rack-registry.js +138 -0
- package/dist/src/registry/file-rack-registry.js.map +1 -0
- package/dist/src/registry/file-rack-registry.spec.d.ts +6 -0
- package/dist/src/registry/file-rack-registry.spec.d.ts.map +1 -0
- package/dist/src/registry/file-rack-registry.spec.js +50 -0
- package/dist/src/registry/file-rack-registry.spec.js.map +1 -0
- package/dist/src/registry/rack-registry.d.ts +64 -0
- package/dist/src/registry/rack-registry.d.ts.map +1 -0
- package/dist/src/registry/rack-registry.js +65 -0
- package/dist/src/registry/rack-registry.js.map +1 -0
- package/dist/src/registry/rack-registry.spec.d.ts +6 -0
- package/dist/src/registry/rack-registry.spec.d.ts.map +1 -0
- package/dist/src/registry/rack-registry.spec.js +8 -0
- package/dist/src/registry/rack-registry.spec.js.map +1 -0
- package/dist/src/routing/eligibility.d.ts +38 -0
- package/dist/src/routing/eligibility.d.ts.map +1 -0
- package/dist/src/routing/eligibility.js +78 -0
- package/dist/src/routing/eligibility.js.map +1 -0
- package/dist/src/routing/host-coupling.d.ts +26 -0
- package/dist/src/routing/host-coupling.d.ts.map +1 -0
- package/dist/src/routing/host-coupling.js +62 -0
- package/dist/src/routing/host-coupling.js.map +1 -0
- package/dist/src/routing/policy.d.ts +188 -0
- package/dist/src/routing/policy.d.ts.map +1 -0
- package/dist/src/routing/policy.js +212 -0
- package/dist/src/routing/policy.js.map +1 -0
- package/dist/src/routing/routing.spec.d.ts +6 -0
- package/dist/src/routing/routing.spec.d.ts.map +1 -0
- package/dist/src/routing/routing.spec.js +100 -0
- package/dist/src/routing/routing.spec.js.map +1 -0
- package/dist/src/routing/tiers.d.ts +22 -0
- package/dist/src/routing/tiers.d.ts.map +1 -0
- package/dist/src/routing/tiers.js +26 -0
- package/dist/src/routing/tiers.js.map +1 -0
- package/dist/src/runner/api-server.d.ts +45 -0
- package/dist/src/runner/api-server.d.ts.map +1 -0
- package/dist/src/runner/api-server.js +21 -0
- package/dist/src/runner/api-server.js.map +1 -0
- package/dist/src/runner/capacity.d.ts +13 -0
- package/dist/src/runner/capacity.d.ts.map +1 -0
- package/dist/src/runner/capacity.js +18 -0
- package/dist/src/runner/capacity.js.map +1 -0
- package/dist/src/runner/rack-body.d.ts +43 -0
- package/dist/src/runner/rack-body.d.ts.map +1 -0
- package/dist/src/runner/rack-body.js +208 -0
- package/dist/src/runner/rack-body.js.map +1 -0
- package/dist/src/runner/rack-runner.d.ts +62 -0
- package/dist/src/runner/rack-runner.d.ts.map +1 -0
- package/dist/src/runner/rack-runner.js +75 -0
- package/dist/src/runner/rack-runner.js.map +1 -0
- package/dist/src/runner/rack-runner.spec.d.ts +6 -0
- package/dist/src/runner/rack-runner.spec.d.ts.map +1 -0
- package/dist/src/runner/rack-runner.spec.js +302 -0
- package/dist/src/runner/rack-runner.spec.js.map +1 -0
- package/dist/src/runner/split.spec.d.ts +6 -0
- package/dist/src/runner/split.spec.d.ts.map +1 -0
- package/dist/src/runner/split.spec.js +188 -0
- package/dist/src/runner/split.spec.js.map +1 -0
- package/dist/src/runner-event.d.ts +261 -0
- package/dist/src/runner-event.d.ts.map +1 -0
- package/dist/src/runner-event.js +332 -0
- package/dist/src/runner-event.js.map +1 -0
- package/dist/src/server/beast2.d.ts +19 -0
- package/dist/src/server/beast2.d.ts.map +1 -0
- package/dist/src/server/beast2.js +18 -0
- package/dist/src/server/beast2.js.map +1 -0
- package/dist/src/server/body-limit.d.ts +16 -0
- package/dist/src/server/body-limit.d.ts.map +1 -0
- package/dist/src/server/body-limit.js +53 -0
- package/dist/src/server/body-limit.js.map +1 -0
- package/dist/src/server/body-limit.spec.d.ts +2 -0
- package/dist/src/server/body-limit.spec.d.ts.map +1 -0
- package/dist/src/server/body-limit.spec.js +32 -0
- package/dist/src/server/body-limit.spec.js.map +1 -0
- package/dist/src/server/bounded.d.ts +16 -0
- package/dist/src/server/bounded.d.ts.map +1 -0
- package/dist/src/server/bounded.js +39 -0
- package/dist/src/server/bounded.js.map +1 -0
- package/dist/src/server/dispatch.d.ts +137 -0
- package/dist/src/server/dispatch.d.ts.map +1 -0
- package/dist/src/server/dispatch.js +267 -0
- package/dist/src/server/dispatch.js.map +1 -0
- package/dist/src/server/env-publication.d.ts +45 -0
- package/dist/src/server/env-publication.d.ts.map +1 -0
- package/dist/src/server/env-publication.js +10 -0
- package/dist/src/server/env-publication.js.map +1 -0
- package/dist/src/server/index.d.ts +16 -0
- package/dist/src/server/index.d.ts.map +1 -0
- package/dist/src/server/index.js +17 -0
- package/dist/src/server/index.js.map +1 -0
- package/dist/src/server/protocol.spec.d.ts +6 -0
- package/dist/src/server/protocol.spec.d.ts.map +1 -0
- package/dist/src/server/protocol.spec.js +78 -0
- package/dist/src/server/protocol.spec.js.map +1 -0
- package/dist/src/server/rack-routes.d.ts +175 -0
- package/dist/src/server/rack-routes.d.ts.map +1 -0
- package/dist/src/server/rack-routes.js +755 -0
- package/dist/src/server/rack-routes.js.map +1 -0
- package/dist/src/server/rack-routes.spec.d.ts +6 -0
- package/dist/src/server/rack-routes.spec.d.ts.map +1 -0
- package/dist/src/server/rack-routes.spec.js +477 -0
- package/dist/src/server/rack-routes.spec.js.map +1 -0
- package/dist/src/server/storage-bridge.d.ts +140 -0
- package/dist/src/server/storage-bridge.d.ts.map +1 -0
- package/dist/src/server/storage-bridge.js +6 -0
- package/dist/src/server/storage-bridge.js.map +1 -0
- package/dist/src/state-file.d.ts +10 -0
- package/dist/src/state-file.d.ts.map +1 -0
- package/dist/src/state-file.js +38 -0
- package/dist/src/state-file.js.map +1 -0
- package/dist/src/testing/in-memory.d.ts +116 -0
- package/dist/src/testing/in-memory.d.ts.map +1 -0
- package/dist/src/testing/in-memory.js +193 -0
- package/dist/src/testing/in-memory.js.map +1 -0
- package/dist/src/testing/index.d.ts +14 -0
- package/dist/src/testing/index.d.ts.map +1 -0
- package/dist/src/testing/index.js +14 -0
- package/dist/src/testing/index.js.map +1 -0
- package/dist/src/testing/lease-store-contract.d.ts +14 -0
- package/dist/src/testing/lease-store-contract.d.ts.map +1 -0
- package/dist/src/testing/lease-store-contract.js +78 -0
- package/dist/src/testing/lease-store-contract.js.map +1 -0
- package/dist/src/testing/protocol-suite.d.ts +38 -0
- package/dist/src/testing/protocol-suite.d.ts.map +1 -0
- package/dist/src/testing/protocol-suite.js +207 -0
- package/dist/src/testing/protocol-suite.js.map +1 -0
- package/dist/src/testing/rack-registry-contract.d.ts +15 -0
- package/dist/src/testing/rack-registry-contract.d.ts.map +1 -0
- package/dist/src/testing/rack-registry-contract.js +106 -0
- package/dist/src/testing/rack-registry-contract.js.map +1 -0
- package/dist/src/testing/test-rack-agent.d.ts +121 -0
- package/dist/src/testing/test-rack-agent.d.ts.map +1 -0
- package/dist/src/testing/test-rack-agent.js +316 -0
- package/dist/src/testing/test-rack-agent.js.map +1 -0
- package/dist/src/tls/tls.d.ts +67 -0
- package/dist/src/tls/tls.d.ts.map +1 -0
- package/dist/src/tls/tls.js +200 -0
- package/dist/src/tls/tls.js.map +1 -0
- package/dist/src/tls/tls.spec.d.ts +6 -0
- package/dist/src/tls/tls.spec.d.ts.map +1 -0
- package/dist/src/tls/tls.spec.js +101 -0
- package/dist/src/tls/tls.spec.js.map +1 -0
- package/dist/src/version.d.ts +9 -0
- package/dist/src/version.d.ts.map +1 -0
- package/dist/src/version.js +10 -0
- package/dist/src/version.js.map +1 -0
- package/package.json +67 -7
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
import { it } from 'node:test';
|
|
6
|
+
import assert from 'node:assert/strict';
|
|
7
|
+
import { mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
8
|
+
import { tmpdir } from 'node:os';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
import { East, IntegerType, StringType, encodeBeast2For, encodeEastIR, equalFor, none, some, variant } from '@elaraai/east';
|
|
11
|
+
import { InMemoryStorage, uuidv7 } from '@elaraai/e3-core';
|
|
12
|
+
import { TASK_OBJECT_KIND, TaskObjectType } from '@elaraai/e3-types';
|
|
13
|
+
import { DEFAULT_RACK_POLICY, RackPolicyError, RackPolicyType, loadPolicy, policyPath, removeRule, savePolicy, selectTask, setEnabled, setMode, setRule } from './policy.js';
|
|
14
|
+
import { rackTierFor } from './tiers.js';
|
|
15
|
+
import { collectPlatformNames, hostCoupledPlatforms } from './host-coupling.js';
|
|
16
|
+
import { EligibilityEvaluator } from './eligibility.js';
|
|
17
|
+
it('matches whole names, literal punctuation, wildcards, and first-rule precedence', () => {
|
|
18
|
+
let policy = setRule(DEFAULT_RACK_POLICY, 'train', 'rack');
|
|
19
|
+
assert.equal(selectTask(policy, 'train').target, 'rack');
|
|
20
|
+
assert.equal(selectTask(policy, 'train_xgb').target, 'local');
|
|
21
|
+
policy = setRule(policy, 'train_*', 'local');
|
|
22
|
+
policy = setRule(policy, '*', 'rack', { size: 'small', timeoutMinutes: 12 });
|
|
23
|
+
assert.equal(selectTask(policy, 'train_xgb').target, 'local');
|
|
24
|
+
assert.equal(selectTask(policy, 'other').size, 'small');
|
|
25
|
+
assert.equal(selectTask(policy, 'other').timeoutMinutes, 12);
|
|
26
|
+
assert.equal(selectTask(policy, 'train').size, 'large');
|
|
27
|
+
assert.equal(selectTask(policy, 'train').timeoutMinutes, 1440);
|
|
28
|
+
const literal = setRule(DEFAULT_RACK_POLICY, 'task[?].*', 'rack');
|
|
29
|
+
assert.equal(selectTask(literal, 'task[x].anything').target, 'rack');
|
|
30
|
+
assert.equal(selectTask(literal, 'taskxx.anything').target, 'local');
|
|
31
|
+
assert.equal(selectTask(literal, 'task[xx].anything').target, 'local');
|
|
32
|
+
assert.equal(selectTask(setMode(DEFAULT_RACK_POLICY, 'auto'), 'anything').target, 'rack');
|
|
33
|
+
assert.equal(removeRule(policy, 'train').rules.length, 2);
|
|
34
|
+
assert.equal(setRule(policy, 'train', 'local').rules.length, 3);
|
|
35
|
+
assert.equal(DEFAULT_RACK_POLICY.rules.length, 0);
|
|
36
|
+
});
|
|
37
|
+
it('round-trips policy and refuses corrupt or invalid values with a remedy', async (t) => {
|
|
38
|
+
const repo = await mkdtemp(join(tmpdir(), 'e3r-'));
|
|
39
|
+
t.after(() => rm(repo, { recursive: true, force: true }));
|
|
40
|
+
assert.ok(equalFor(RackPolicyType)(await loadPolicy(repo), DEFAULT_RACK_POLICY));
|
|
41
|
+
const policy = setEnabled(setRule(DEFAULT_RACK_POLICY, 'train_*', 'rack'), true);
|
|
42
|
+
await savePolicy(repo, policy);
|
|
43
|
+
assert.ok(equalFor(RackPolicyType)(await loadPolicy(repo), policy));
|
|
44
|
+
await assert.rejects(savePolicy(repo, { ...policy, claimTimeoutSeconds: -1n }), RackPolicyError);
|
|
45
|
+
await writeFile(policyPath(repo), 'corrupt');
|
|
46
|
+
await assert.rejects(loadPolicy(repo), (err) => err instanceof RackPolicyError && err.message.includes(policyPath(repo)) && err.message.includes('reset'));
|
|
47
|
+
});
|
|
48
|
+
it('maps only each runtime’s own stock platforms to a rack tier', () => {
|
|
49
|
+
const decode = variant('lazy', null);
|
|
50
|
+
assert.deepEqual(rackTierFor(variant('east_node', { platforms: [], decode })), { tier: 'node' });
|
|
51
|
+
assert.deepEqual(rackTierFor(variant('east_node', { platforms: ['@elaraai/east-node-std', '@elaraai/east-node-io'], decode })), { tier: 'node' });
|
|
52
|
+
assert.deepEqual(rackTierFor(variant('east_py', { platforms: ['east-py-std', 'east-py-io'], decode })), { tier: 'py' });
|
|
53
|
+
assert.deepEqual(rackTierFor(variant('east_py', { platforms: ['east-py-datascience'], decode })), { tier: 'py-datascience' });
|
|
54
|
+
assert.deepEqual(rackTierFor(variant('east_c', { platforms: ['east-c-std'], decode })), { tier: 'c' });
|
|
55
|
+
assert.deepEqual(rackTierFor(variant('east_node', { platforms: ['east-py-std'], decode })), { ineligible: 'non-stock-platform:east-py-std' });
|
|
56
|
+
assert.deepEqual(rackTierFor(variant('east_py', { platforms: ['mine'], decode })), { ineligible: 'non-stock-platform:mine' });
|
|
57
|
+
assert.deepEqual(rackTierFor(variant('custom', { command: ['mine'] })), { ineligible: 'custom-runner' });
|
|
58
|
+
});
|
|
59
|
+
const fetchGet = East.asyncPlatform('fetch_get', [StringType], StringType);
|
|
60
|
+
const envGet = East.platform('env_get', [StringType], StringType);
|
|
61
|
+
const sync = East.function([StringType], StringType, ($, value) => envGet(value));
|
|
62
|
+
const asyncNested = East.asyncFunction([StringType], StringType, ($, value) => {
|
|
63
|
+
const helper = $.const(East.asyncFunction([StringType], StringType, ($, url) => fetchGet(url)));
|
|
64
|
+
return helper(value);
|
|
65
|
+
});
|
|
66
|
+
it('scans sync and nested async programs and distinguishes JSON text from host files', () => {
|
|
67
|
+
assert.deepEqual(collectPlatformNames(encodeEastIR(sync.toIR())), ['env_get']);
|
|
68
|
+
assert.deepEqual(collectPlatformNames(encodeEastIR(asyncNested.toIR())), ['fetch_get']);
|
|
69
|
+
assert.deepEqual(hostCoupledPlatforms(['fs_read_file', 'json_open', 'json_value', 'json_open_text', 'path_resolve', 'console_log', 'crypto_uuid', 'random_normal', 'time_now']), ['fs_read_file', 'json_open', 'json_value', 'path_resolve']);
|
|
70
|
+
assert.throws(() => collectPlatformNames(new Uint8Array([1])));
|
|
71
|
+
});
|
|
72
|
+
it('checks reducers even when the first request is a merge with cached maps', async () => {
|
|
73
|
+
const storage = new InMemoryStorage();
|
|
74
|
+
await storage.repos.create('repo');
|
|
75
|
+
const pure = East.function([IntegerType], IntegerType, ($, value) => value.add(1n));
|
|
76
|
+
const program = await storage.objects.write('repo', encodeEastIR(pure.toIR()));
|
|
77
|
+
const reducer = await storage.objects.write('repo', encodeEastIR(sync.toIR()));
|
|
78
|
+
const task = {
|
|
79
|
+
kind: TASK_OBJECT_KIND, body: variant('east', { program }),
|
|
80
|
+
runner: variant('east_node', { platforms: ['@elaraai/east-node-std'], decode: variant('lazy', null) }),
|
|
81
|
+
inputs: [], output: { path: [], kind: variant('dict', { merge: some(reducer) }) }, role: variant('data', null), environment: none,
|
|
82
|
+
};
|
|
83
|
+
const hash = await storage.objects.write('repo', encodeBeast2For(TaskObjectType)(task));
|
|
84
|
+
const request = { storage, repo: 'repo', taskHash: hash, task, inputHashes: ['merge'],
|
|
85
|
+
ids: { inHash: 'a'.repeat(64), executionId: uuidv7(), startTime: Date.now() }, options: { taskName: 'train' },
|
|
86
|
+
role: 'unit', logicalTaskHash: hash, unit: { inputs: ['merge'], merge: { parts: [], range: null }, own: false } };
|
|
87
|
+
const policy = setRule(DEFAULT_RACK_POLICY, 'train', 'rack');
|
|
88
|
+
const evaluator = new EligibilityEvaluator(policy);
|
|
89
|
+
assert.deepEqual(await evaluator.evaluate(request), { eligible: false, reason: 'host-coupled:env_get' });
|
|
90
|
+
assert.deepEqual(await evaluator.evaluate({ ...request, role: 'task' }), { eligible: false, reason: 'host-coupled:env_get' });
|
|
91
|
+
assert.deepEqual(await evaluator.evaluate({ ...request, options: {} }), { eligible: false, reason: 'no-task-name' });
|
|
92
|
+
assert.deepEqual(await evaluator.evaluate({ ...request, options: { taskName: 'other' } }), { eligible: false, reason: 'not-selected' });
|
|
93
|
+
const override = new EligibilityEvaluator(setRule(policy, 'train', 'rack', { allowHostCoupled: true }));
|
|
94
|
+
assert.deepEqual(await override.evaluate(request), { eligible: true, tier: 'node', size: 'large', timeoutMinutes: 1440 });
|
|
95
|
+
const envTask = { ...task, environment: some('b'.repeat(64)) };
|
|
96
|
+
assert.deepEqual(await new EligibilityEvaluator(policy).evaluate({ ...request, task: envTask }), { eligible: false, reason: 'environment' });
|
|
97
|
+
const badTask = { ...task, body: variant('east', { program: 'c'.repeat(64) }) };
|
|
98
|
+
assert.deepEqual(await new EligibilityEvaluator(policy).evaluate({ ...request, task: badTask }), { eligible: false, reason: 'unscannable' });
|
|
99
|
+
});
|
|
100
|
+
//# sourceMappingURL=routing.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routing.spec.js","sourceRoot":"","sources":["../../../src/routing/routing.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
import type { RunnerValue } from '@elaraai/e3-types';
|
|
6
|
+
/** Stock runtime images available to rack agents. */
|
|
7
|
+
export type RackTier = 'node' | 'py' | 'py-datascience' | 'c';
|
|
8
|
+
/** A stable reason an execution stays on the local host. */
|
|
9
|
+
export type IneligibleReason = 'no-task-name' | 'not-selected' | 'environment' | 'custom-runner' | `non-stock-platform:${string}` | `host-coupled:${string}` | 'unscannable';
|
|
10
|
+
/**
|
|
11
|
+
* Chooses a stock runtime image, refusing project-specific commands/packages.
|
|
12
|
+
* @param runner - The task's wire runner
|
|
13
|
+
* @returns Its tier, or the reason it cannot run on the rack
|
|
14
|
+
* @example
|
|
15
|
+
* const route = rackTierFor(task.runner);
|
|
16
|
+
*/
|
|
17
|
+
export declare function rackTierFor(runner: RunnerValue): {
|
|
18
|
+
tier: RackTier;
|
|
19
|
+
} | {
|
|
20
|
+
ineligible: IneligibleReason;
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=tiers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tiers.d.ts","sourceRoot":"","sources":["../../../src/routing/tiers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,qDAAqD;AACrD,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,IAAI,GAAG,gBAAgB,GAAG,GAAG,CAAC;AAC9D,4DAA4D;AAC5D,MAAM,MAAM,gBAAgB,GAAG,cAAc,GAAG,cAAc,GAAG,aAAa,GAAG,eAAe,GAC5F,sBAAsB,MAAM,EAAE,GAAG,gBAAgB,MAAM,EAAE,GAAG,aAAa,CAAC;AAE9E;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAAG;IAAE,UAAU,EAAE,gBAAgB,CAAA;CAAE,CAUtG"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
import { STOCK_PLATFORMS_BY_RUNNER } from '@elaraai/e3';
|
|
6
|
+
/**
|
|
7
|
+
* Chooses a stock runtime image, refusing project-specific commands/packages.
|
|
8
|
+
* @param runner - The task's wire runner
|
|
9
|
+
* @returns Its tier, or the reason it cannot run on the rack
|
|
10
|
+
* @example
|
|
11
|
+
* const route = rackTierFor(task.runner);
|
|
12
|
+
*/
|
|
13
|
+
export function rackTierFor(runner) {
|
|
14
|
+
if (runner.type === 'custom')
|
|
15
|
+
return { ineligible: 'custom-runner' };
|
|
16
|
+
const stock = STOCK_PLATFORMS_BY_RUNNER[runner.type];
|
|
17
|
+
const unknown = runner.value.platforms.find((name) => !stock.includes(name));
|
|
18
|
+
if (unknown !== undefined)
|
|
19
|
+
return { ineligible: `non-stock-platform:${unknown}` };
|
|
20
|
+
switch (runner.type) {
|
|
21
|
+
case 'east_node': return { tier: 'node' };
|
|
22
|
+
case 'east_c': return { tier: 'c' };
|
|
23
|
+
case 'east_py': return { tier: runner.value.platforms.includes('east-py-datascience') ? 'py-datascience' : 'py' };
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=tiers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tiers.js","sourceRoot":"","sources":["../../../src/routing/tiers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AASxD;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,MAAmB;IAC7C,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ;QAAE,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,CAAC;IACrE,MAAM,KAAK,GAAsB,yBAAyB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACxE,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;IAC7E,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,EAAE,UAAU,EAAE,sBAAsB,OAAO,EAAE,EAAE,CAAC;IAClF,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC;QACpB,KAAK,WAAW,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QAC1C,KAAK,QAAQ,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;QACpC,KAAK,SAAS,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACpH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
import type { Budget, StorageBackend, TaskRunner } from '@elaraai/e3-core';
|
|
6
|
+
/**
|
|
7
|
+
* What the server lends one dataflow run: e3-api-server's
|
|
8
|
+
* `DataflowRunnerLease`, declared here so this package needs nothing of the
|
|
9
|
+
* server, whose optional peer it is.
|
|
10
|
+
*/
|
|
11
|
+
export interface DataflowRunnerLease {
|
|
12
|
+
/** Runs the tasks and units in this run. */
|
|
13
|
+
runner: TaskRunner;
|
|
14
|
+
/** Adds remote capacity to the orchestrator's width, without enlarging its local budget. */
|
|
15
|
+
extraConcurrency: number;
|
|
16
|
+
/** Releases the attachment once, on success, failure, cancellation or failed start. */
|
|
17
|
+
close(): Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The server's `dataflowRunner` option: e3-api-server's
|
|
21
|
+
* `DataflowRunnerFactory`, structurally, given the server's own backend and
|
|
22
|
+
* budget; undefined or a thrown error uses the server's local runner.
|
|
23
|
+
*/
|
|
24
|
+
export type DataflowRunnerFactory = (repoPath: string, workspace: string, context: {
|
|
25
|
+
storage: StorageBackend;
|
|
26
|
+
budget: Budget;
|
|
27
|
+
}) => Promise<DataflowRunnerLease | undefined>;
|
|
28
|
+
/** Configures labels and an optional isolated home for server attachments. */
|
|
29
|
+
export interface DataflowRackOptions {
|
|
30
|
+
/** Prefixes the workspace and process id in rack status. */
|
|
31
|
+
labelPrefix?: string;
|
|
32
|
+
/** Overrides the user-wide rack home. */
|
|
33
|
+
home?: string;
|
|
34
|
+
/** Overrides the ten-second compatible-capacity startup wait. */
|
|
35
|
+
waitForRackMs?: number;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Creates one rack session per API dataflow run on the server's existing budget.
|
|
39
|
+
* Explicit server opt-in ignores policy.enabled; each repository's rules and
|
|
40
|
+
* routing mode still select eligible tasks. Calls and mutations remain local.
|
|
41
|
+
* @param options - Session labels and optional isolated deployment settings
|
|
42
|
+
* @returns A factory for createServer's dataflowRunner option
|
|
43
|
+
*/
|
|
44
|
+
export declare function createDataflowRunnerFactory(options?: DataflowRackOptions): DataflowRunnerFactory;
|
|
45
|
+
//# sourceMappingURL=api-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-server.d.ts","sourceRoot":"","sources":["../../../src/runner/api-server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAG3E;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,4CAA4C;IAC5C,MAAM,EAAE,UAAU,CAAC;IACnB,4FAA4F;IAC5F,gBAAgB,EAAE,MAAM,CAAC;IACzB,uFAAuF;IACvF,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED;;;;GAIG;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE;IAAE,OAAO,EAAE,cAAc,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,KAAK,OAAO,CAAC,mBAAmB,GAAG,SAAS,CAAC,CAAC;AAE5K,8EAA8E;AAC9E,MAAM,WAAW,mBAAmB;IAClC,4DAA4D;IAC5D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yCAAyC;IACzC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,GAAE,mBAAwB,GAAG,qBAAqB,CAOpG"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
import { openRackRunner } from './rack-runner.js';
|
|
6
|
+
/**
|
|
7
|
+
* Creates one rack session per API dataflow run on the server's existing budget.
|
|
8
|
+
* Explicit server opt-in ignores policy.enabled; each repository's rules and
|
|
9
|
+
* routing mode still select eligible tasks. Calls and mutations remain local.
|
|
10
|
+
* @param options - Session labels and optional isolated deployment settings
|
|
11
|
+
* @returns A factory for createServer's dataflowRunner option
|
|
12
|
+
*/
|
|
13
|
+
export function createDataflowRunnerFactory(options = {}) {
|
|
14
|
+
return async (repoPath, workspace, { storage, budget }) => {
|
|
15
|
+
const rack = await openRackRunner({ repoPath, workspace, storage, budget,
|
|
16
|
+
label: `${options.labelPrefix ?? 'e3-api-server'} ${workspace} (pid ${process.pid})`,
|
|
17
|
+
home: options.home, waitForRackMs: options.waitForRackMs });
|
|
18
|
+
return { runner: rack.runner, extraConcurrency: rack.rackSlots, close: () => rack.close() };
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=api-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-server.js","sourceRoot":"","sources":["../../../src/runner/api-server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAiClD;;;;;;GAMG;AACH,MAAM,UAAU,2BAA2B,CAAC,UAA+B,EAAE;IAC3E,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE;QACxD,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM;YACtE,KAAK,EAAE,GAAG,OAAO,CAAC,WAAW,IAAI,eAAe,IAAI,SAAS,SAAS,OAAO,CAAC,GAAG,GAAG;YACpF,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,aAAa,EAAE,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC;QAC9D,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,gBAAgB,EAAE,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC;IAC9F,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
import type { CapacitySnapshot } from '../protocol/control.js';
|
|
6
|
+
/**
|
|
7
|
+
* Selects healthy, approved racks able to boot this run's e3 release.
|
|
8
|
+
* @param capacity - The hub's current fleet
|
|
9
|
+
* @param tier - Required runtime, or every runtime when omitted
|
|
10
|
+
* @returns Compatible registrations in their reported order
|
|
11
|
+
*/
|
|
12
|
+
export declare function compatibleRacks(capacity: CapacitySnapshot, tier?: string): CapacitySnapshot['racks'];
|
|
13
|
+
//# sourceMappingURL=capacity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capacity.d.ts","sourceRoot":"","sources":["../../../src/runner/capacity.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAI/D;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,gBAAgB,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAIpG"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
import { agentVersionAtLeast } from '../protocol/index.js';
|
|
6
|
+
import { E3_RACK_VERSION } from '../version.js';
|
|
7
|
+
/**
|
|
8
|
+
* Selects healthy, approved racks able to boot this run's e3 release.
|
|
9
|
+
* @param capacity - The hub's current fleet
|
|
10
|
+
* @param tier - Required runtime, or every runtime when omitted
|
|
11
|
+
* @returns Compatible registrations in their reported order
|
|
12
|
+
*/
|
|
13
|
+
export function compatibleRacks(capacity, tier) {
|
|
14
|
+
return capacity.racks.filter((rack) => rack.healthy && !rack.pendingApproval &&
|
|
15
|
+
rack.bundledE3.type === 'some' && agentVersionAtLeast(rack.bundledE3.value, E3_RACK_VERSION) &&
|
|
16
|
+
(tier === undefined || rack.tiers.includes(tier)) && Number(rack.capacity) > 0);
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=capacity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capacity.js","sourceRoot":"","sources":["../../../src/runner/capacity.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,QAA0B,EAAE,IAAa;IACvE,OAAO,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,eAAe;QAC1E,IAAI,CAAC,SAAS,CAAC,IAAI,KAAK,MAAM,IAAI,mBAAmB,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,eAAe,CAAC;QAC5F,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;AACpF,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
import { type TaskBodyExecutor } from '@elaraai/e3-core';
|
|
6
|
+
import type { RackSession } from '../client/session.js';
|
|
7
|
+
import type { RackPolicy } from '../routing/policy.js';
|
|
8
|
+
/** Reports the placement of one task body or split unit. */
|
|
9
|
+
export type RackPlacementEvent = {
|
|
10
|
+
taskName: string;
|
|
11
|
+
role: 'task' | 'unit';
|
|
12
|
+
where: 'rack';
|
|
13
|
+
rackLabel: string;
|
|
14
|
+
leaseId: string;
|
|
15
|
+
} | {
|
|
16
|
+
taskName: string;
|
|
17
|
+
role: 'task' | 'unit';
|
|
18
|
+
where: 'local';
|
|
19
|
+
reason: string;
|
|
20
|
+
};
|
|
21
|
+
/** Configures a run's body executor without acquiring local resources. */
|
|
22
|
+
export interface RackBodyOptions {
|
|
23
|
+
/** Live session serving this repository. */
|
|
24
|
+
session: RackSession;
|
|
25
|
+
/** Policy snapshot for this run. */
|
|
26
|
+
policy: RackPolicy;
|
|
27
|
+
/** Workspace named on the rack's activity view. */
|
|
28
|
+
workspace: string;
|
|
29
|
+
/** Disables capacity spill, but still permits infrastructure fallback. */
|
|
30
|
+
rackOnly?: boolean;
|
|
31
|
+
/** Receives placement and fallback notifications. */
|
|
32
|
+
onPlacement?: (event: RackPlacementEvent) => void;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Delegates eligible cache misses through the shared hub. The hub alone
|
|
36
|
+
* writes the remote attempt; local() owns every local fallback and grant.
|
|
37
|
+
* @param options - Session, policy and placement sink
|
|
38
|
+
* @returns The body hook for e3-core's LocalTaskRunner
|
|
39
|
+
* @example
|
|
40
|
+
* const runner = new LocalTaskRunner(repo, budget, { body: createRackBody({ session, policy, workspace: 'dev' }) });
|
|
41
|
+
*/
|
|
42
|
+
export declare function createRackBody(options: RackBodyOptions): TaskBodyExecutor;
|
|
43
|
+
//# sourceMappingURL=rack-body.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rack-body.d.ts","sourceRoot":"","sources":["../../../src/runner/rack-body.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAkE,KAAK,gBAAgB,EAAwB,MAAM,kBAAkB,CAAC;AAC/I,OAAO,KAAK,EAA4B,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAKlF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAIvD,4DAA4D;AAC5D,MAAM,MAAM,kBAAkB,GAC1B;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC9F;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEhF,0EAA0E;AAC1E,MAAM,WAAW,eAAe;IAC9B,4CAA4C;IAC5C,OAAO,EAAE,WAAW,CAAC;IACrB,oCAAoC;IACpC,MAAM,EAAE,UAAU,CAAC;IACnB,mDAAmD;IACnD,SAAS,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,qDAAqD;IACrD,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;CACnD;AAuBD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,eAAe,GAAG,gBAAgB,CA4IzE"}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
import { ExecutionAttempt, touchReachable, uuidv7 } from '@elaraai/e3-core';
|
|
6
|
+
import { recordClosure, stagedObjects, taskClosure } from '../lease/closure.js';
|
|
7
|
+
import { RACK_LEASE_VERSION } from '../protocol/task-envelope.js';
|
|
8
|
+
import { splitUnitToWire } from '../runner-event.js';
|
|
9
|
+
import { EligibilityEvaluator } from '../routing/eligibility.js';
|
|
10
|
+
import { E3_RACK_VERSION } from '../version.js';
|
|
11
|
+
import { compatibleRacks } from './capacity.js';
|
|
12
|
+
/** Whether this body could obtain a local core and its memory reservation. */
|
|
13
|
+
function localIdle(request) {
|
|
14
|
+
const budget = request.options.budget;
|
|
15
|
+
if (budget === undefined)
|
|
16
|
+
return true;
|
|
17
|
+
const memory = request.options.expectedPeakBytes ?? 0;
|
|
18
|
+
return budget.queued === 0 && budget.inFlight < budget.cores &&
|
|
19
|
+
(memory > budget.memory ? budget.inFlight === 0 : budget.used + memory <= budget.memory);
|
|
20
|
+
}
|
|
21
|
+
/** Waits without abandoning a pending next() when a timer wins the race. */
|
|
22
|
+
function wait(next, ms, signal) {
|
|
23
|
+
if (signal?.aborted)
|
|
24
|
+
return Promise.resolve('abort');
|
|
25
|
+
return new Promise((resolve, reject) => {
|
|
26
|
+
const finish = (value) => { clearTimeout(timer); signal?.removeEventListener('abort', abort); resolve(value); };
|
|
27
|
+
const abort = () => finish('abort');
|
|
28
|
+
const timer = setTimeout(() => finish('tick'), Math.max(1, Math.min(ms, 2147483647)));
|
|
29
|
+
signal?.addEventListener('abort', abort, { once: true });
|
|
30
|
+
next.then(finish, (error) => { clearTimeout(timer); signal?.removeEventListener('abort', abort); reject(error); });
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Delegates eligible cache misses through the shared hub. The hub alone
|
|
35
|
+
* writes the remote attempt; local() owns every local fallback and grant.
|
|
36
|
+
* @param options - Session, policy and placement sink
|
|
37
|
+
* @returns The body hook for e3-core's LocalTaskRunner
|
|
38
|
+
* @example
|
|
39
|
+
* const runner = new LocalTaskRunner(repo, budget, { body: createRackBody({ session, policy, workspace: 'dev' }) });
|
|
40
|
+
*/
|
|
41
|
+
export function createRackBody(options) {
|
|
42
|
+
const { session, policy } = options;
|
|
43
|
+
const evaluator = new EligibilityEvaluator(policy);
|
|
44
|
+
return async (request, local) => {
|
|
45
|
+
const placement = { taskName: request.options.taskName ?? request.taskHash, role: request.role };
|
|
46
|
+
let handle;
|
|
47
|
+
let rackLabel = 'rack';
|
|
48
|
+
let untee;
|
|
49
|
+
let leavingRack = false;
|
|
50
|
+
const freshIds = () => ({ inHash: request.ids.inHash, executionId: uuidv7(), startTime: Date.now() });
|
|
51
|
+
const stop = (kind, cause) => {
|
|
52
|
+
leavingRack = true;
|
|
53
|
+
return new ExecutionAttempt(request.storage, request.repo, request.taskHash, request.inputHashes, freshIds(), request.unit !== undefined && !request.unit.own).recordStopped(kind, cause);
|
|
54
|
+
};
|
|
55
|
+
const runLocal = async (reason) => {
|
|
56
|
+
leavingRack = true;
|
|
57
|
+
if (handle !== undefined)
|
|
58
|
+
await handle.cancel().catch(() => { });
|
|
59
|
+
const ids = handle === undefined ? request.ids : freshIds();
|
|
60
|
+
options.onPlacement?.({ ...placement, where: 'local', reason });
|
|
61
|
+
if (reason.startsWith('fallback:')) {
|
|
62
|
+
const line = `e3: rack attempt failed on ${rackLabel}: ${reason.slice(9)} — running locally\n`;
|
|
63
|
+
await request.storage.logs.append(request.repo, request.taskHash, ids.inHash, ids.executionId, 'stderr', line);
|
|
64
|
+
request.options.onStderr?.(line);
|
|
65
|
+
}
|
|
66
|
+
return local(ids);
|
|
67
|
+
};
|
|
68
|
+
if (request.options.signal?.aborted)
|
|
69
|
+
return local();
|
|
70
|
+
if (session.hubLost)
|
|
71
|
+
return runLocal('hub-unreachable');
|
|
72
|
+
const verdict = await evaluator.evaluate(request);
|
|
73
|
+
if (!verdict.eligible)
|
|
74
|
+
return runLocal(verdict.reason);
|
|
75
|
+
// An explicitly configured host process environment or identity cannot be
|
|
76
|
+
// reproduced by a stock guest. Keep these settings on the standard body.
|
|
77
|
+
if (request.options.env !== undefined || request.options.uid !== undefined || request.options.gid !== undefined ||
|
|
78
|
+
(request.options.extraEnv !== undefined && Object.keys(request.options.extraEnv).length > 0))
|
|
79
|
+
return runLocal('host-process-settings');
|
|
80
|
+
if (compatibleRacks(session.capacity(), verdict.tier).length === 0)
|
|
81
|
+
return runLocal(`no-rack-for-tier:${verdict.tier}`);
|
|
82
|
+
const canSpill = () => policy.spill && !options.rackOnly && localIdle(request);
|
|
83
|
+
// The compatible slots free in the latest snapshot, less the work already queued for them.
|
|
84
|
+
const freeSlots = () => {
|
|
85
|
+
const snapshot = session.capacity();
|
|
86
|
+
return compatibleRacks(snapshot, verdict.tier).reduce((sum, rack) => sum + Number(rack.capacity) - Number(rack.busy), 0) - Number(snapshot.queued);
|
|
87
|
+
};
|
|
88
|
+
try {
|
|
89
|
+
const hashes = await taskClosure(request.storage, request.repo, request.taskHash, request.task, request.unit === undefined ? request.inputHashes : stagedObjects(request.unit.inputs, request.unit.merge));
|
|
90
|
+
const closure = await recordClosure(request.storage, request.repo, hashes);
|
|
91
|
+
const timeoutMs = Math.min(verdict.timeoutMinutes * 60000, request.options.timeout ?? Infinity);
|
|
92
|
+
const common = { launchId: uuidv7(), repo: session.repoAlias, timeoutMs,
|
|
93
|
+
taskHash: request.taskHash, force: true, verbose: request.options.verbose === true,
|
|
94
|
+
...(request.options.expectedPeakBytes !== undefined && { expectedPeakBytes: request.options.expectedPeakBytes }) };
|
|
95
|
+
const event = { version: RACK_LEASE_VERSION,
|
|
96
|
+
runnerEvent: request.unit === undefined ? { ...common, mode: 'task', inputHashes: request.inputHashes }
|
|
97
|
+
: { ...common, mode: 'unit', unit: splitUnitToWire(request.unit) },
|
|
98
|
+
workspace: options.workspace, taskName: placement.taskName, e3Version: E3_RACK_VERSION, closure };
|
|
99
|
+
if (request.options.signal?.aborted)
|
|
100
|
+
return await stop('cancelled', 'cancelled: e3 did not start the rack execution because the run was aborted');
|
|
101
|
+
const lease = { eventJson: JSON.stringify(event), tier: verdict.tier, computeSize: verdict.size };
|
|
102
|
+
if (freeSlots() <= 0 && canSpill()) {
|
|
103
|
+
// The racks are full. Identical work already queued or held costs them
|
|
104
|
+
// no further capacity, so attach to it; anything else runs locally now,
|
|
105
|
+
// without first queuing a lease a rack could claim before the spill.
|
|
106
|
+
const attached = await session.attachLease(lease);
|
|
107
|
+
if (attached === null)
|
|
108
|
+
return await runLocal('spill');
|
|
109
|
+
handle = attached;
|
|
110
|
+
}
|
|
111
|
+
else
|
|
112
|
+
handle = await session.createLease(lease);
|
|
113
|
+
const claimWait = Number(policy.claimTimeoutSeconds) * 1000;
|
|
114
|
+
let claimDeadline = Date.now() + claimWait;
|
|
115
|
+
let executionDeadline;
|
|
116
|
+
let next = handle.next();
|
|
117
|
+
for (;;) {
|
|
118
|
+
const update = await wait(next, (executionDeadline ?? claimDeadline) - Date.now(), request.options.signal);
|
|
119
|
+
if (update === 'abort') {
|
|
120
|
+
await handle.cancel().catch(() => { });
|
|
121
|
+
return await stop('cancelled', 'cancelled: e3 stopped waiting for the rack execution because the run was aborted');
|
|
122
|
+
}
|
|
123
|
+
if (update === 'tick') {
|
|
124
|
+
if (executionDeadline !== undefined) {
|
|
125
|
+
if (Date.now() < executionDeadline)
|
|
126
|
+
continue;
|
|
127
|
+
await handle.cancel().catch(() => { });
|
|
128
|
+
return await stop('error', `timed out: the task exceeded ${verdict.timeoutMinutes} min on rack ${rackLabel}`);
|
|
129
|
+
}
|
|
130
|
+
await session.refreshCapacity();
|
|
131
|
+
if (compatibleRacks(session.capacity(), verdict.tier).length === 0)
|
|
132
|
+
return await runLocal('fallback:rack-unavailable');
|
|
133
|
+
if (canSpill())
|
|
134
|
+
return await runLocal('fallback:not-claimed');
|
|
135
|
+
claimDeadline = Date.now() + claimWait;
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
if (update.kind === 'claimed') {
|
|
139
|
+
rackLabel = update.rackLabel;
|
|
140
|
+
// The host owns the deadline; the rack's clock does not determine it.
|
|
141
|
+
executionDeadline ??= Date.now() + common.timeoutMs;
|
|
142
|
+
untee?.();
|
|
143
|
+
untee = session.onLog(update.attempt.executionId, (stream, text) => {
|
|
144
|
+
if (stream === 'stdout')
|
|
145
|
+
request.options.onStdout?.(text);
|
|
146
|
+
else
|
|
147
|
+
request.options.onStderr?.(text);
|
|
148
|
+
});
|
|
149
|
+
options.onPlacement?.({ ...placement, where: 'rack', rackLabel, leaseId: handle.leaseId });
|
|
150
|
+
next = handle.next();
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
if (update.kind === 'lost')
|
|
154
|
+
return await runLocal(`fallback:${update.reason}`);
|
|
155
|
+
if (update.kind === 'cancelled') {
|
|
156
|
+
// This session left the lease: by the run's abort, or by closing
|
|
157
|
+
// under a run that was not aborted, whose work then finishes locally.
|
|
158
|
+
if (request.options.signal?.aborted)
|
|
159
|
+
return await stop('cancelled', 'cancelled: e3 left the rack execution because the run was aborted');
|
|
160
|
+
return await runLocal('fallback:rack session closed');
|
|
161
|
+
}
|
|
162
|
+
const result = update.result;
|
|
163
|
+
if (update.attempt === null)
|
|
164
|
+
return await runLocal('fallback:missing-attempt');
|
|
165
|
+
const attempt = update.attempt;
|
|
166
|
+
const duration = () => Date.now() - request.ids.startTime;
|
|
167
|
+
const peak = result.peakBytes !== undefined ? { peakBytes: result.peakBytes } : {};
|
|
168
|
+
if (result.cancelled === true) {
|
|
169
|
+
// To e3-core a cancelled result is its own abort's: the task goes back
|
|
170
|
+
// to pending, and a loop that was not aborted launches it again at
|
|
171
|
+
// once. Only this run's abort is one. A rack that stopped the attempt
|
|
172
|
+
// for a reason of its own did not run it, and the work runs locally.
|
|
173
|
+
if (!request.options.signal?.aborted)
|
|
174
|
+
return await runLocal(`fallback:${result.error ?? 'the rack stopped the attempt'}`);
|
|
175
|
+
return { inputsHash: request.ids.inHash, executionId: attempt.executionId, cached: false, state: 'error', outputHash: null,
|
|
176
|
+
exitCode: result.exitCode ?? null, duration: duration(), error: result.error ?? null, cancelled: true, ...peak };
|
|
177
|
+
}
|
|
178
|
+
const state = result.state ?? (result.status === 'success' ? 'success' : (result.exitCode ?? 0) > 0 ? 'failed' : 'error');
|
|
179
|
+
if (state === 'success') {
|
|
180
|
+
if (result.outputHash === undefined || !await touchReachable(request.storage, request.repo, [result.outputHash]))
|
|
181
|
+
return await runLocal('fallback:incomplete-output');
|
|
182
|
+
return { inputsHash: request.ids.inHash, executionId: attempt.executionId, cached: false, state, outputHash: result.outputHash,
|
|
183
|
+
exitCode: 0, duration: duration(), error: result.error ?? null, cancelled: false, ...peak };
|
|
184
|
+
}
|
|
185
|
+
// e3-core, which the rack ran, records its own timeout as an error whose
|
|
186
|
+
// message begins `timed out:` (as an abort's begins `cancelled:`). The
|
|
187
|
+
// task would use its time up again here, so that error stands. Any
|
|
188
|
+
// other error is the rack's, and the work runs locally; a task's own
|
|
189
|
+
// failure is its verdict, whatever its message mentions, unless the
|
|
190
|
+
// policy retries failures locally.
|
|
191
|
+
const timedOut = state === 'error' && /^timed out:/.test(result.error ?? '');
|
|
192
|
+
if (state === 'error' ? !timedOut : policy.retryTaskFailuresLocally)
|
|
193
|
+
return await runLocal(`fallback:${result.error ?? 'rack execution failed'}`);
|
|
194
|
+
return { inputsHash: request.ids.inHash, executionId: attempt.executionId, cached: false, state, outputHash: null,
|
|
195
|
+
exitCode: result.exitCode ?? null, duration: duration(), error: result.error ?? null, cancelled: false, ...peak };
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
catch (error) {
|
|
199
|
+
if (leavingRack)
|
|
200
|
+
throw error;
|
|
201
|
+
return await runLocal(`fallback:${error instanceof Error ? error.message : String(error)}`);
|
|
202
|
+
}
|
|
203
|
+
finally {
|
|
204
|
+
untee?.();
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
//# sourceMappingURL=rack-body.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rack-body.js","sourceRoot":"","sources":["../../../src/runner/rack-body.ts"],"names":[],"mappings":"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"}
|