discopt.gams.daemon#
Warm solver daemon for the discopt GAMS link.
GAMS launches a solver as a fresh process per solve, so each solve otherwise re-pays Python + JAX import and first-JIT warmup (seconds), even though a warm solve is ~10 ms. This module keeps a single long-lived process warm and turns the per-solve launch into a thin socket round-trip.
Pieces#
DaemonServer– listens on a per-user unix socket, services one request at a time (solves are serialized: one warm interpreter, GIL + JAX thread-safety), and self-terminates on idle timeout / max lifetime / max solves / version mismatch.solve_via_daemon()– the client used by the GAMS link: connect (lazily spawning a detached daemon if needed), relay the control-file path, return the exit code. ReturnsNoneto signal the caller should fall back to an in-process solve, so correctness never depends on the daemon being up.
The lifecycle (idle timeout + lazy auto-respawn + direct-solve fallback) is exercised in tests with a fake solve function, so it needs no GAMS install.
Classes#
A warm, single-request-at-a-time solver server over a unix socket. |
Functions#
|
Per-user socket path (honours |
|
Return the running daemon's handshake, or |
|
Ask a running daemon to shut down. Returns True if it acknowledged. |
|
Start a detached daemon and wait until its socket answers. |
|
Solve |
|
|
Module Contents#
- discopt.gams.daemon.default_socket_path() pathlib.Path#
Per-user socket path (honours
DISCOPT_GAMS_SOCKET/XDG_RUNTIME_DIR).
- class discopt.gams.daemon.DaemonServer(socket_path: pathlib.Path | None = None, solve_fn: collections.abc.Callable[[str, str | None], int] | None = None, idle_timeout: float | None = None, max_lifetime: float | None = None, max_solves: int | None = None, max_rss_mb: int | None = None, jax_clear_every: int | None = None, version: str = __version__)#
A warm, single-request-at-a-time solver server over a unix socket.
- socket_path#
- idle_timeout#
- max_lifetime#
- max_solves#
- max_rss_mb#
- jax_clear_every#
- version = '0.4.1.dev0'#
- solves = 0#
- serve_forever() None#
Accept and service requests until a shutdown condition fires.
- discopt.gams.daemon.ping(socket_path: pathlib.Path | None = None) dict | None#
Return the running daemon’s handshake, or
Noneif not reachable.
- discopt.gams.daemon.stop_daemon(socket_path: pathlib.Path | None = None) bool#
Ask a running daemon to shut down. Returns True if it acknowledged.
- discopt.gams.daemon.spawn_daemon(socket_path: pathlib.Path | None = None, wait: float = _SPAWN_WAIT) bool#
Start a detached daemon and wait until its socket answers.
- discopt.gams.daemon.solve_via_daemon(control_file: str, sysdir: str | None = None, socket_path: pathlib.Path | None = None) int | None#
Solve
control_filethrough the warm daemon, spawning it if needed.Returns the solver exit code, or
Noneif the daemon is unreachable and could not be started – the caller should then solve in-process.
- discopt.gams.daemon.main(argv: list[str] | None = None) int#
python -m discopt.gams.daemon {serve,stop,status}.