Skip to content

Commit bdeba23

Browse files
committed
Standardize solver packaging and server fixtures
1 parent b5c43c9 commit bdeba23

31 files changed

Lines changed: 347 additions & 562 deletions

.github/workflows/package.yml

Lines changed: 96 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ env:
1717
NODE_VERSION: 24.12.0
1818
DENO_VERSION: 2.8.1
1919
BUN_VERSION: 1.3.14
20+
ORTOOLS_SERVER_IMAGE: ortools-wasm-native-server:ci
21+
ORTOOLS_WASM_SKIP_PACKAGE_BUILD: '1'
2022

2123
jobs:
2224
package:
@@ -31,13 +33,15 @@ jobs:
3133
submodules: recursive
3234

3335
- name: Setup Node
36+
if: ${{ !env.ACT }}
3437
uses: actions/setup-node@v6
3538
with:
3639
node-version: ${{ env.NODE_VERSION }}
3740
cache: npm
3841
cache-dependency-path: package/package-lock.json
3942

4043
- name: Cache Emscripten and CMake build
44+
if: ${{ !env.ACT }}
4145
uses: actions/cache@v4
4246
with:
4347
path: |
@@ -52,18 +56,25 @@ jobs:
5256
wasm-build-${{ runner.os }}-
5357
5458
- name: Install dependencies
59+
if: ${{ !env.ACT }}
5560
run: npm ci --prefix package
5661

5762
- name: Install native build tools
63+
if: ${{ !env.ACT }}
5864
run: sudo apt-get update && sudo apt-get install -y cmake ninja-build
5965

6066
- name: Prepare package README for release tag
6167
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
6268
run: node scripts/prepare_package_readme.mjs "$GITHUB_REF_NAME"
6369

6470
- name: Build and pack library
71+
if: ${{ !env.ACT }}
6572
run: npm --prefix package run pack:lib
6673

74+
- name: Require locally packed library
75+
if: ${{ env.ACT }}
76+
run: test -n "$(find package/build/javascript/lib -maxdepth 1 -name '*.tgz' -print -quit)"
77+
6778
- name: Upload package artifact
6879
if: ${{ !env.ACT }}
6980
uses: actions/upload-artifact@v7
@@ -125,7 +136,7 @@ jobs:
125136

126137
- name: Run Vite fixture
127138
working-directory: package
128-
run: NODE_PATH=./node_modules FIXTURE_GROUP=vite npx playwright test --config ../tests/playwright.config.ts --project=${{ matrix.project }}
139+
run: NODE_PATH=./node_modules FIXTURE_GROUP=vite npx playwright test --config tests/playwright.config.ts --project=${{ matrix.project }}
129140

130141
webpack-fixture:
131142
name: Webpack 5 / ${{ matrix.mode }} / ${{ matrix.browser }}
@@ -179,7 +190,7 @@ jobs:
179190

180191
- name: Run Webpack fixture
181192
working-directory: package
182-
run: NODE_PATH=./node_modules FIXTURE_GROUP=webpack npx playwright test --config ../tests/playwright.config.ts --project=${{ matrix.project }}
193+
run: NODE_PATH=./node_modules FIXTURE_GROUP=webpack npx playwright test --config tests/playwright.config.ts --project=${{ matrix.project }}
183194

184195
rollup-fixture:
185196
name: Rollup 4 / static / ${{ matrix.browser }}
@@ -225,7 +236,7 @@ jobs:
225236

226237
- name: Run Rollup fixture
227238
working-directory: package
228-
run: NODE_PATH=./node_modules FIXTURE_GROUP=rollup npx playwright test --config ../tests/playwright.config.ts --project=${{ matrix.project }}
239+
run: NODE_PATH=./node_modules FIXTURE_GROUP=rollup npx playwright test --config tests/playwright.config.ts --project=${{ matrix.project }}
229240

230241
deno-fixture:
231242
name: Deno 2.8.1 / solve
@@ -327,6 +338,87 @@ jobs:
327338
- name: Run Bun fixture
328339
run: npm --prefix package run test:fixture:bun
329340

341+
server-fixture:
342+
name: Native server / JavaScript client
343+
needs: package
344+
runs-on: ubuntu-24.04
345+
timeout-minutes: 90
346+
347+
steps:
348+
- name: Checkout
349+
uses: actions/checkout@v6
350+
with:
351+
submodules: recursive
352+
353+
- name: Setup Node
354+
uses: actions/setup-node@v6
355+
with:
356+
node-version: ${{ env.NODE_VERSION }}
357+
cache: npm
358+
cache-dependency-path: package/package-lock.json
359+
360+
- name: Install dependencies
361+
run: npm ci --prefix package
362+
363+
- name: Download package artifact
364+
if: ${{ !env.ACT }}
365+
uses: actions/download-artifact@v8
366+
with:
367+
name: npm-package
368+
path: package/build/javascript/lib
369+
370+
- name: Setup Docker Buildx
371+
if: ${{ !env.ACT }}
372+
uses: docker/setup-buildx-action@v3
373+
374+
- name: Build native server image
375+
if: ${{ !env.ACT }}
376+
uses: docker/build-push-action@v6
377+
with:
378+
context: .
379+
file: server/Dockerfile
380+
tags: ${{ env.ORTOOLS_SERVER_IMAGE }}
381+
load: true
382+
cache-from: type=gha,scope=native-server
383+
cache-to: type=gha,mode=max,scope=native-server
384+
385+
- name: Build native server image with local cache
386+
if: ${{ env.ACT }}
387+
run: docker build --file server/Dockerfile --tag "${ORTOOLS_SERVER_IMAGE}" .
388+
389+
- name: Start native server
390+
run: docker compose -f server/docker-compose.yml up -d --no-build ortools-native
391+
392+
- name: Require healthy native server
393+
run: |
394+
for attempt in $(seq 1 60); do
395+
if curl --fail --silent --show-error http://127.0.0.1:17827/healthz; then
396+
exit 0
397+
fi
398+
sleep 1
399+
done
400+
echo "Native server did not become healthy." >&2
401+
exit 1
402+
403+
- name: Build Vite fixture
404+
run: npm --prefix package run test:fixture:vite:build
405+
406+
- name: Install Chromium
407+
working-directory: package
408+
run: npx playwright install --with-deps chromium
409+
410+
- name: Run fixture against native server
411+
working-directory: package
412+
run: ORTOOLS_TEST_SERVER=1 NODE_PATH=./node_modules FIXTURE_GROUP=vite npx playwright test --config tests/playwright.config.ts --project=vite-static-chromium
413+
414+
- name: Show native server logs
415+
if: ${{ always() }}
416+
run: docker compose -f server/docker-compose.yml logs --no-color ortools-native
417+
418+
- name: Stop native server
419+
if: ${{ always() }}
420+
run: docker compose -f server/docker-compose.yml down --remove-orphans
421+
330422
publish:
331423
name: Publish release
332424
needs:
@@ -337,6 +429,7 @@ jobs:
337429
- deno-fixture
338430
- node-fixture
339431
- bun-fixture
432+
- server-fixture
340433
runs-on: ubuntu-24.04
341434
timeout-minutes: 10
342435
if: ${{ startsWith(github.ref, 'refs/tags/v') && github.actor != 'nektos/act' }}

.github/workflows/server.yml

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ jobs:
2727
submodules: recursive
2828

2929
- name: Setup Docker Buildx
30+
if: ${{ !env.ACT }}
3031
uses: docker/setup-buildx-action@v3
3132

3233
- name: Build native server image
@@ -42,16 +43,7 @@ jobs:
4243

4344
- name: Build native server image with local cache
4445
if: ${{ env.ACT }}
45-
run: |
46-
docker buildx build \
47-
--file server/Dockerfile \
48-
--tag "${ORTOOLS_SERVER_IMAGE}" \
49-
--load \
50-
--cache-from type=local,src=/tmp/ortools-wasm-native-server-cache \
51-
--cache-to type=local,dest=/tmp/ortools-wasm-native-server-cache-next,mode=max \
52-
.
53-
rm -rf /tmp/ortools-wasm-native-server-cache
54-
mv /tmp/ortools-wasm-native-server-cache-next /tmp/ortools-wasm-native-server-cache
46+
run: docker build --file server/Dockerfile --tag "${ORTOOLS_SERVER_IMAGE}" .
5547

5648
- name: Run native server tests
5749
run: docker compose -f server/docker-compose.yml run --rm ortools-native-test

javascript/lib/cp_sat/worker_executor.ts

Lines changed: 4 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,11 @@ import {
66
type CpSatExecutorRequest,
77
} from './executor.js';
88

9-
declare const __ORTOOLS_WASM_BROWSER_BUILD__: boolean | undefined;
10-
11-
const isDeno = 'Deno' in globalThis;
12-
const isBun = 'Bun' in globalThis;
13-
const isNode = typeof process !== 'undefined' && typeof process.versions?.node === 'string' && !isDeno && !isBun;
14-
159
async function createCpSatWorker(): Promise<WorkerLike<Uint8Array, Uint8Array>> {
16-
if (typeof __ORTOOLS_WASM_BROWSER_BUILD__ !== 'undefined' && __ORTOOLS_WASM_BROWSER_BUILD__) {
17-
return new Worker(new URL('./worker.js', import.meta.url), {
18-
type: 'module',
19-
name: 'ortools-executor-cp-sat',
20-
});
21-
}
22-
if (isNode || isDeno) {
23-
const { Worker: NodeWorker } = await import('node:worker_threads');
24-
return new NodeWorker(
25-
new URL('./cp_sat_node_worker_bridge.js', import.meta.url),
26-
{ execArgv: [] },
27-
) as WorkerLike<Uint8Array, Uint8Array>;
28-
}
29-
return new Worker(new URL('./worker.js', import.meta.url), {
30-
type: 'module',
31-
name: 'ortools-executor-cp-sat',
32-
});
10+
return new Worker(
11+
new URL('./worker.js', import.meta.url),
12+
{ type: 'module', name: 'ortools-executor-cp-sat' },
13+
);
3314
}
3415

3516
export class CpSatWorkerExecutor

javascript/lib/executor_configuration.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,7 @@ export type ExecutorConfiguration =
3131
export type ResolvedExecutorConfiguration = Exclude<ExecutorConfiguration, AutoExecutorConfiguration>;
3232

3333
const isBrowserMainThread = typeof window !== 'undefined' && typeof document !== 'undefined';
34-
const isDeno = 'Deno' in globalThis;
35-
const isBun = 'Bun' in globalThis;
36-
const isNode = typeof process !== 'undefined' && typeof process.versions?.node === 'string' && !isDeno && !isBun;
37-
const isWorkerAvailable = ((isBrowserMainThread || isDeno || isBun) && typeof Worker !== 'undefined') || isNode;
34+
const isWorkerAvailable = typeof Worker !== 'undefined';
3835

3936
export function resolveExecutorConfiguration(
4037
configuration: ExecutorConfiguration = { type: 'auto' },

javascript/lib/internal_wasm_asyncify.d.ts

Lines changed: 0 additions & 15 deletions
This file was deleted.

javascript/lib/knapsack/worker_executor.ts

Lines changed: 4 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,11 @@ import { SolverWorkerExecutor, type WorkerLike } from '../worker_helpers.js';
22
import type { KnapsackBridgeRequest, KnapsackBridgeResponse } from '../generated/bridge/knapsack_pb.js';
33
import { knapsackBridgeCodec, type KnapsackExecutorLike } from './executor.js';
44

5-
declare const __ORTOOLS_WASM_BROWSER_BUILD__: boolean | undefined;
6-
7-
const isDeno = 'Deno' in globalThis;
8-
const isBun = 'Bun' in globalThis;
9-
const isNode = typeof process !== 'undefined' && typeof process.versions?.node === 'string' && !isDeno && !isBun;
10-
115
async function createKnapsackWorker(): Promise<WorkerLike<Uint8Array, Uint8Array>> {
12-
if (typeof __ORTOOLS_WASM_BROWSER_BUILD__ !== 'undefined' && __ORTOOLS_WASM_BROWSER_BUILD__) {
13-
return new Worker(new URL('./worker.js', import.meta.url), {
14-
type: 'module',
15-
name: 'ortools-executor-knapsack',
16-
});
17-
}
18-
if (isNode || isDeno) {
19-
const { Worker: NodeWorker } = await import('node:worker_threads');
20-
return new NodeWorker(
21-
new URL('./knapsack_node_worker_bridge.js', import.meta.url),
22-
{ execArgv: [] },
23-
) as WorkerLike<Uint8Array, Uint8Array>;
24-
}
25-
return new Worker(new URL('./worker.js', import.meta.url), {
26-
type: 'module',
27-
name: 'ortools-executor-knapsack',
28-
});
6+
return new Worker(
7+
new URL('./worker.js', import.meta.url),
8+
{ type: 'module', name: 'ortools-executor-knapsack' },
9+
);
2910
}
3011

3112
export class KnapsackWorkerExecutor

javascript/lib/mathopt.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export {
2424
PdlpParameters,
2525
PdlpRestartStrategy,
2626
PdlpSchedulerType,
27-
} from './mathopt_api.js';
27+
} from './mathopt/api.js';
2828
export type {
2929
GlopParametersOptions,
3030
GlpkParametersOptions,
@@ -51,6 +51,6 @@ export type {
5151
MathOptVariable,
5252
MathOptVariableOptions,
5353
PdlpParametersOptions,
54-
} from './mathopt_api.js';
54+
} from './mathopt/api.js';
5555
export type { ExecutorConfiguration } from './executor_configuration.js';
5656
export { terminateLoadedRuntimeThreads } from './runtime_loader.js';
Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
import { create } from '@bufbuild/protobuf';
2-
import type { ExecutorConfiguration, ResolvedExecutorConfiguration } from './executor_configuration.js';
3-
import { resolveExecutorConfiguration } from './executor_configuration.js';
2+
import type { ExecutorConfiguration, ResolvedExecutorConfiguration } from '../executor_configuration.js';
3+
import { resolveExecutorConfiguration } from '../executor_configuration.js';
44
import {
55
MathOptIncrementalCreateRequestSchema,
66
MathOptIncrementalDeleteRequestSchema,
77
MathOptIncrementalSolveRequestSchema,
88
MathOptSolveRequestSchema,
9-
} from './generated/bridge/mathopt_pb.js';
10-
import type { SolverJobEvent } from './solver_executor.js';
11-
import { MathOptExecutor, type MathOptExecutorLike, type MathOptExecutorRequest } from './mathopt/executor.js';
12-
import { MathOptServerExecutor } from './mathopt/server_executor.js';
13-
import { MathOptWorkerExecutor } from './mathopt/worker_executor.js';
14-
import type { SatParameters } from './generated/sat_parameters.js';
9+
} from '../generated/bridge/mathopt_pb.js';
10+
import type { SolverJobEvent } from '../solver_executor.js';
11+
import { MathOptExecutor, type MathOptExecutorLike, type MathOptExecutorRequest } from './executor.js';
12+
import { MathOptServerExecutor } from './server_executor.js';
13+
import { MathOptWorkerExecutor } from './worker_executor.js';
14+
import type { SatParameters } from '../generated/sat_parameters.js';
1515

1616
type WireValue = Uint8Array;
1717

javascript/lib/mathopt/worker_executor.ts

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,16 @@ import type { MathOptBridgeResponse } from '../generated/bridge/mathopt_pb.js';
22
import { SolverWorkerExecutor, type WorkerLike } from '../worker_helpers.js';
33
import { mathOptBridgeCodec, type MathOptExecutorLike, type MathOptExecutorRequest } from './executor.js';
44

5-
declare const __ORTOOLS_WASM_BROWSER_BUILD__: boolean | undefined;
6-
const isDeno = 'Deno' in globalThis;
7-
const isBun = 'Bun' in globalThis;
8-
const isNode = typeof process !== 'undefined' && typeof process.versions?.node === 'string' && !isDeno && !isBun;
95
async function createWorker(): Promise<WorkerLike<Uint8Array, Uint8Array>> {
10-
if (typeof __ORTOOLS_WASM_BROWSER_BUILD__ !== 'undefined' && __ORTOOLS_WASM_BROWSER_BUILD__) return new Worker(new URL('./worker.js', import.meta.url), { type: 'module', name: 'ortools-executor-mathopt' });
11-
if (isNode || isDeno) {
12-
const { Worker: NodeWorker } = await import('node:worker_threads');
13-
return new NodeWorker(new URL('./mathopt_node_worker_bridge.js', import.meta.url), { execArgv: [] }) as WorkerLike<Uint8Array, Uint8Array>;
14-
}
15-
return new Worker(new URL('./worker.js', import.meta.url), { type: 'module', name: 'ortools-executor-mathopt' });
6+
return new Worker(
7+
new URL('./worker.js', import.meta.url),
8+
{ type: 'module', name: 'ortools-executor-mathopt' },
9+
);
1610
}
17-
export class MathOptWorkerExecutor extends SolverWorkerExecutor<MathOptExecutorRequest, MathOptBridgeResponse, never> implements MathOptExecutorLike {
18-
constructor() { super(mathOptBridgeCodec, createWorker); }
11+
export class MathOptWorkerExecutor
12+
extends SolverWorkerExecutor<MathOptExecutorRequest, MathOptBridgeResponse, never>
13+
implements MathOptExecutorLike {
14+
constructor() {
15+
super(mathOptBridgeCodec, createWorker);
16+
}
1917
}

javascript/lib/mp-solver.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export {
1414
PresolveValues,
1515
ScalingValues,
1616
setMPSolverExecutor as setExecutor,
17-
} from './mp_solver_api.js';
17+
} from './mp_solver/api.js';
1818
export type {
1919
LinearSolverSchemas,
2020
MPSolverModelRequest,
@@ -23,6 +23,6 @@ export type {
2323
MPSolverSolutionResponse,
2424
MPSolverEvent,
2525
MPSolverExecutionOptions,
26-
} from './mp_solver_api.js';
26+
} from './mp_solver/api.js';
2727
export type { ExecutorConfiguration } from './executor_configuration.js';
2828
export { terminateLoadedRuntimeThreads } from './runtime_loader.js';

0 commit comments

Comments
 (0)