REST API for LDES (LINE Discrete Event Simulator). Source: github.com/imperial-qore/ldes
387
Docker packaging of LDES, the discrete-event simulator of the LINE solver, with a REST interface. The image bundles a JRE, so nothing has to be installed on the host: it reads a queueing network model in JSON, simulates it, and returns performance metrics in JSON.
The engine is the GraalVM native image of LDES, executed as a subprocess per
request. It avoids JVM startup entirely, so an M/M/1 model with 20000 events answers in
roughly 60 ms end to end, against roughly 280 ms of JVM startup alone for
java -jar ldes.jar. Each solve being its own process is also what allows the server to
run several concurrently.
docker run --rm -p 8080:8080 imperialqore/ldes-rest
curl -s -X POST http://localhost:8080/api/v1/solve \
-H 'Content-Type: application/json' \
-d '{"model":{"content":"<model.json text>"},"options":{"samples":20000,"seed":42}}'
docker run --rm -v "$PWD:/data" imperialqore/ldes-rest solve model.json -o result.json --seed 42
docker run --rm -v "$PWD:/data" imperialqore/ldes-rest model.json -o result.json # solve is implicit
The container runs as an unprivileged user, so a bind-mounted output directory must be
writable by others, or the container must be started with --user "$(id -u):$(id -g)".
Base path /api/v1.
| Method | Path | Description |
|---|---|---|
| GET | /health | Liveness probe |
| GET | /ready | Readiness probe (engine class resolvable) |
| GET | /info | Server, engine and JVM metadata |
| POST | /solve | Simulate a model, return the ldes-result document |
{
"model": {"content": "<model.json text>", "base64": false},
"options": {"samples": 20000, "seed": 42, "cnvgon": true, "cnvgtol": 0.01},
"flags": ["--trajectory"]
}
model also accepts an inline model object, or a bare JSON string. Each key of
options maps to the LDES long-form flag of the same name: a number or string becomes
--key value, a boolean true becomes the bare switch --key, an array is
comma-joined (--timespan, --initsol). flags is a verbatim escape hatch for
anything the mapping does not cover. -o and --help are rejected: the server owns the
model and result paths.
The response embeds the same ldes-result document the CLI writes to -o:
{
"status": "ok",
"exitCode": 0,
"elapsedMs": 21,
"result": {"format": "ldes-result", "metrics": {"QN": [[0.0], [0.973]], "...": []}},
"stdout": "LDES events: ...",
"stderr": ""
}
Status codes: 200 on success, 400 for a malformed request, 422 when the engine
rejects the model or produces no result, 503 from /ready before the engine is
resolvable.
| Variable | Default | Meaning |
|---|---|---|
LDES_REST_HOST | 0.0.0.0 | Bind address |
LDES_REST_PORT | 8080 | Bind port |
LDES_REST_CONCURRENCY | CPU count | Concurrent engine subprocesses |
LDES_REST_TEMP_DIR | /tmp/ldes-rest | Scratch directory for per-request documents |
LDES_REST_MAX_BODY | 67108864 | Maximum request body in bytes |
LDES_ENGINE | /opt/ldes/ldes | Path to the LDES native image |
JAVA_OPTS | empty | Extra JVM flags for the front end |
Concurrency bounds the engine subprocesses, not the HTTP threads: requests beyond the
limit queue rather than fail. Large state spaces are bounded by the engine's own memory,
not by the front end's heap, so JAVA_OPTS does not need raising for big models.
All three LINE bindings take an explicit solver option naming the server. The model is
serialized to the same model.json the CLI reads, so for a fixed seed and event budget
the remote run is bit-for-bit identical to a local one.
% MATLAB
opts = SolverOptions('LDES');
opts.rest_url = 'http://localhost:8080';
avgTable = SolverLDES(model, opts).getAvgTable();
# Python
from line_solver.solvers.wrappers.solver_ldes import SolverLDES
SolverLDES(model, samples=20000, seed=42, rest_url='http://localhost:8080').getAvgTable()
// Java
LDESOptions opts = new LDESOptions();
opts.setRestUrl("http://localhost:8080");
new SolverLDES(model, opts).getAvgTable();
./build.sh # stage the artifacts, then docker build
./build.sh /path/to/ldes/target imperialqore/ldes-rest:3.0.6
tests/smoke.sh # CLI mode, REST mode, error handling
build.sh takes both artifacts from ../line-dev.git/ldes/target, falling back to
../ldes-standalone.git: the native image ldes is the engine, and ldes.jar is a
build-time input supplying the Gson classes the front end needs, so nothing is fetched
from a network during the build. It refuses an engine that is not an x86-64 ELF
executable, and a jar whose manifest does not name jline.cli.LdesCLI, since concurrent
bundle builds can leave either file half-written.
line-dev.git/upload-ldes.sh runs this build after the GraalVM build and pushes the
image alongside the SourceForge and stand-alone artifacts, so the published image always
carries the engine of the current LINE release. Pass --no-docker to skip that step.
tests/JavaRestParity.java and tests/matlab_rest_parity.m check that a remote solve
matches a local one exactly; both take the server URL as their argument.
Original project: https://line-solver.sourceforge.net/
Source: https://github.com/imperial-qore/ldes
License: BSD-3-Clause
Content type
Image
Digest
sha256:9b5adb9f3…
Size
90.7 MB
Last updated
about 1 month ago
docker pull imperialqore/ldes-rest