Skip to content

Launcher

Runtime plumbing for the packaged app: writable path resolution, the embedded PostgreSQL cluster, lifecycle events and OS-specific process containment.

src.launcher

Launcher support utilities.

The launcher package exposes helpers shared between the cross-platform startup script (backend/run.py) and the rest of the backend stack. It keeps runtime-specific state (like data and log directories) in one place so both the launcher and the FastAPI application resolve paths consistently.

RuntimePaths(mode, backend_root, data_dir, log_dir) dataclass

Resolved directories for the current Erudi process.

ensure_runtime_paths_initialized(backend_root=None)

Ensure runtime paths are initialized, defaulting to development mode.

Parameters:

Name Type Description Default
backend_root Optional[Path]

Explicit backend root directory. When omitted, defaults to the repository layout (backend/).

None

Returns:

Name Type Description
RuntimePaths RuntimePaths

Resolved runtime directories.

Source code in backend/src/launcher/runtime_paths.py
def ensure_runtime_paths_initialized(backend_root: Optional[Path] = None) -> RuntimePaths:
    """Ensure runtime paths are initialized, defaulting to development mode.

    Args:
        backend_root: Explicit backend root directory. When omitted, defaults to
            the repository layout (``backend/``).

    Returns:
        RuntimePaths: Resolved runtime directories.
    """
    global _RUNTIME_PATHS
    if _RUNTIME_PATHS is None:
        root = backend_root or Path(__file__).resolve().parents[2]
        packaged_data = root / "data"
        _RUNTIME_PATHS = _compute_runtime_paths(
            mode="dev", backend_root=root, packaged_data_dir=packaged_data
        )
    return _RUNTIME_PATHS

get_runtime_paths()

Return the current runtime paths.

Returns:

Name Type Description
RuntimePaths RuntimePaths

Current runtime path configuration.

Raises:

Type Description
RuntimeError

If runtime paths were not initialized yet.

Source code in backend/src/launcher/runtime_paths.py
def get_runtime_paths() -> RuntimePaths:
    """Return the current runtime paths.

    Returns:
        RuntimePaths: Current runtime path configuration.

    Raises:
        RuntimeError: If runtime paths were not initialized yet.
    """
    if _RUNTIME_PATHS is None:
        raise RuntimeError("Runtime paths not initialized")
    return _RUNTIME_PATHS

initialize_runtime_paths(mode, backend_root, packaged_data_dir=None)

Initialize runtime paths for the current process.

Parameters:

Name Type Description Default
mode str

Runtime mode, typically "dev" or "prod".

required
backend_root Path

Path to the backend root directory (contains src).

required
packaged_data_dir Optional[Path]

Optional path to the read-only data payload bundled with the application. Only required for bundled builds.

None

Returns:

Name Type Description
RuntimePaths RuntimePaths

Resolved directory information for the process.

Raises:

Type Description
ValueError

If runtime paths are initialized more than once or the mode is unsupported.

Source code in backend/src/launcher/runtime_paths.py
def initialize_runtime_paths(
    mode: str, backend_root: Path, packaged_data_dir: Optional[Path] = None
) -> RuntimePaths:
    """Initialize runtime paths for the current process.

    Args:
        mode: Runtime mode, typically ``"dev"`` or ``"prod"``.
        backend_root: Path to the backend root directory (contains ``src``).
        packaged_data_dir: Optional path to the read-only data payload bundled
            with the application. Only required for bundled builds.

    Returns:
        RuntimePaths: Resolved directory information for the process.

    Raises:
        ValueError: If runtime paths are initialized more than once or the mode
            is unsupported.
    """
    global _RUNTIME_PATHS
    if _RUNTIME_PATHS is not None:
        raise ValueError("Runtime paths already initialized")

    runtime_paths = _compute_runtime_paths(
        mode=mode, backend_root=backend_root, packaged_data_dir=packaged_data_dir
    )
    _RUNTIME_PATHS = runtime_paths
    return runtime_paths

src.launcher.db_watchdog

Embedded-Postgres watchdog: detect a dead cluster, resurrect it, expose state.

The embedded PostgreSQL cluster (src.launcher.postgres_runtime) can die mid-session -- the whole lineage killed externally (a corporate EDR/console cleaner reaping the shared conhost was reproduced on the packaged app, #162). Before this module the app ran as a zombie: /erudi/health/ kept answering {"status": "ok"} (a static reply that never touches the DB) while every DB-backed endpoint 500ed -- 17 observed zombie minutes in the July incident.

Design (validated on #162, PR B):

  • State machine: db_state in {ok, recovering, failed}, a module global read by /health (see get_db_state).
  • Reactive detection: a SQLAlchemy handle_error listener on the live engine flips the state to recovering the instant a request hits a connection-level disconnect. The hook does NOTHING else (no I/O): it flags state and wakes the recovery loop thread-safely.
  • Proactive detection: while healthy the loop probes SELECT 1 every ~30s (off the event loop) so the zero-traffic case (the July incident: no DB request to trip on for 17 minutes) is still caught.
  • Resurrection: on recovering the loop restarts the cluster through the field-proven start_postgres machinery (WAL recovery, the #215 cache eviction, retries) and re-binds the three DB tenants -- SQLAlchemy engine (init_database), the LangGraph checkpointer, and the KB vector store (init_kb_store) -- as a FULL re-init, because a resurrected postmaster may come back on a different port/URI (pool.dispose would keep the stale URI). Backoff ladder 5s/15s/60s; after the third failed attempt the state goes failed and the loop parks until the next error/probe wake.

All log literals are ASCII (repo rule).

get_db_state()

Current DB health as seen by the watchdog: ok | recovering | failed.

Source code in backend/src/launcher/db_watchdog.py
def get_db_state() -> str:
    """Current DB health as seen by the watchdog: ok | recovering | failed."""
    return db_state

start_watchdog(app)

Start the watchdog: attach the disconnect hook + spawn the recovery loop.

Call AFTER init_database has bound the live engine (the hook attaches to core.db_engine) and the checkpointer is open on app.state. Idempotent: a second call is a no-op while the loop is running.

Source code in backend/src/launcher/db_watchdog.py
def start_watchdog(app: FastAPI) -> None:
    """Start the watchdog: attach the disconnect hook + spawn the recovery loop.

    Call AFTER ``init_database`` has bound the live engine (the hook attaches to
    ``core.db_engine``) and the checkpointer is open on ``app.state``.
    Idempotent: a second call is a no-op while the loop is running.
    """
    global _app, _loop_task, _wake, _event_loop, db_state
    if _loop_task is not None and not _loop_task.done():
        return
    _app = app
    _event_loop = asyncio.get_running_loop()
    _wake = asyncio.Event()
    db_state = DB_OK
    _register_error_listener()
    _loop_task = asyncio.create_task(_recovery_loop())

stop_watchdog() async

Stop the watchdog cleanly: cancel + await the loop, detach the hook.

Source code in backend/src/launcher/db_watchdog.py
async def stop_watchdog() -> None:
    """Stop the watchdog cleanly: cancel + await the loop, detach the hook."""
    global _loop_task, _app, _wake, _event_loop
    task = _loop_task
    _loop_task = None
    if task is not None:
        task.cancel()
        try:
            await task
        except asyncio.CancelledError:
            pass
    _remove_error_listener()
    _app = None
    _wake = None
    _event_loop = None
    logger.info("DB watchdog stopped")

src.launcher.events

Shared newline-delimited JSON lifecycle-event emitter.

Both the cross-platform launcher (backend/run.py) and the FastAPI lifespan run in the same process and share stdout. The Electron main process (frontend/src/main.js) parses each stdout line as JSON and tolerates interleaved non-JSON log lines. Keeping a single emitter here means the launcher and the app agree on the wire format, and startup progress (phase) events can originate from inside the lifespan.

Event shapes
  • {"event": "starting", ...} (run.py)
  • {"event": "phase", "phase": ""} (lifespan, via emit_phase)
  • {"event": "ready", "port": N} (run.py)
  • {"event": "shutdown"} (run.py)
  • {"event": "startup_error", "code": "...", ...} (run.py)
  • {"event": "engine_notice", "code": "...", "gpu_name": "...", "compute_capability": "...", "driver_cuda_version": "...", "required_cuda_version": "...", "raw": "..."} (lifespan)

engine_notice reports a GPU the bundled CUDA build cannot drive. It is NOT a startup failure: the backend is healthy and serving, and the frontend holds the event until after ready to show it as a decision (run on the processor instead, or update the driver) rather than an error screen.

Every emitted event additionally carries a ts field (UTC ISO-8601 with milliseconds and a Z suffix, e.g. 2026-07-02T09:15:32.123Z) so the Electron log (new Date().toISOString()) and the backend log can be correlated on a single timeline.

emit_event(payload)

Print a structured JSON lifecycle event (newline-delimited) to stdout.

A ts field (UTC ISO-8601 ms, Z) is stamped on every event; the caller's payload is not mutated.

Source code in backend/src/launcher/events.py
def emit_event(payload: dict) -> None:
    """Print a structured JSON lifecycle event (newline-delimited) to stdout.

    A ``ts`` field (UTC ISO-8601 ms, Z) is stamped on every event; the
    caller's payload is not mutated.
    """
    print(json.dumps({**payload, "ts": _utc_timestamp()}), flush=True)

emit_phase(phase)

Emit a startup-progress phase the frontend can surface on the loader.

Phases are informational only — the frontend still gates readiness on the ready event / a confirming health check, never on a phase.

Source code in backend/src/launcher/events.py
def emit_phase(phase: str) -> None:
    """Emit a startup-progress phase the frontend can surface on the loader.

    Phases are informational only — the frontend still gates readiness on the
    ``ready`` event / a confirming health check, never on a phase.
    """
    emit_event({"event": "phase", "phase": phase})

src.launcher.postgres_runtime

Embedded PostgreSQL runtime (pgserver) lifecycle for Erudi.

Starts/stops the local cluster bundled by the pgserver wheel (no Docker, no system install), ensures the erudi database and the pgvector extension exist, and derives the two URL forms consumed by the stack:

  • sqlalchemy_url — postgresql+psycopg://… for the sync SQLAlchemy engine (business layer) and langchain-postgres PGEngine.
  • psycopg_url — postgresql://… for AsyncPostgresSaver and raw psycopg connections.

pgserver defaults to a Unix-domain-socket URI (…?host=<socket dir>) on POSIX; get_server is idempotent (initdb on first run, refcounted across processes) and registers an atexit cleanup. We still stop the cluster explicitly from the FastAPI lifespan shutdown for a deterministic order (checkpointer first, cluster last).

Authentication (#462). pgserver runs initdb --auth=trust --auth-local=trust and, on Windows, where there are no Unix sockets, starts the postmaster on a loopback TCP port -- so any process under the user's account could open the database with no credential. Every start_postgres therefore generates a random password once per cluster (<data_dir>/erudi_db_password), sets it on the postgres role, rewrites pg_hba.conf so every host rule requires scram-sha-256 (local socket rules stay trust: filesystem permissions guard the socket), reloads the postmaster, and carries the password in both derived URLs. The same code runs on every platform so the POSIX test suites exercise it too; only the TCP refusal itself is Windows-only.

PostgresHandle(server, data_dir, psycopg_url, sqlalchemy_url) dataclass

Live embedded-cluster handle with the two derived connection URLs.

harden_pg_hba(text)

Rewrite pg_hba.conf so every host rule authenticates with SCRAM.

Pure text -> text: trust on a host* line becomes scram-sha-256; local (Unix socket) rules, comments, blank lines, spacing and every other method are left byte-for-byte as they were. Idempotent.

Source code in backend/src/launcher/postgres_runtime.py
def harden_pg_hba(text: str) -> str:
    """Rewrite ``pg_hba.conf`` so every ``host`` rule authenticates with SCRAM.

    Pure text -> text: ``trust`` on a ``host*`` line becomes ``scram-sha-256``;
    ``local`` (Unix socket) rules, comments, blank lines, spacing and every
    other method are left byte-for-byte as they were. Idempotent.
    """
    return _TRUSTED_HOST_RULE.sub(r"\g<rule>scram-sha-256\g<rest>", text)

postmaster_log_tail(data_dir, max_lines=POSTMASTER_LOG_TAIL_LINES)

The embedded postmaster's own last lines, or "" when it wrote none.

Reads a bounded window from the end of the file (the log is unbounded), drops the partial line that window starts on, and redacts any password literal PostgreSQL echoed from a failing statement.

Decoded defensively: Postgres writes its messages in the server encoding and in the operating system's language, so a byte that is not UTF-8 must cost a character, never the whole diagnostic. Never raises -- an absent or unreadable file simply has nothing to say.

Source code in backend/src/launcher/postgres_runtime.py
def postmaster_log_tail(data_dir: Path | str, max_lines: int = POSTMASTER_LOG_TAIL_LINES) -> str:
    """The embedded postmaster's own last lines, or ``""`` when it wrote none.

    Reads a bounded window from the end of the file (the log is unbounded),
    drops the partial line that window starts on, and redacts any password
    literal PostgreSQL echoed from a failing statement.

    Decoded defensively: Postgres writes its messages in the server encoding
    and in the operating system's language, so a byte that is not UTF-8 must
    cost a character, never the whole diagnostic. Never raises -- an absent or
    unreadable file simply has nothing to say.
    """
    log_file = Path(data_dir) / POSTMASTER_LOG_NAME
    try:
        size = log_file.stat().st_size
        start = max(0, size - POSTMASTER_LOG_WINDOW_BYTES)
        with log_file.open("rb") as handle:
            if start:
                handle.seek(start)
            raw = handle.read(POSTMASTER_LOG_WINDOW_BYTES)
    except OSError:
        return ""
    text = raw.decode("utf-8", errors="replace")
    if start:
        # The window landed mid-line; that fragment belongs to a line whose
        # beginning was not read.
        _, _, text = text.partition("\n")
    lines = [line for line in text.splitlines() if line.strip()]
    tail = _redact_passwords("\n".join(lines[-max_lines:]))
    return tail[-POSTMASTER_LOG_TAIL_CHARS:] if len(tail) > POSTMASTER_LOG_TAIL_CHARS else tail

start_postgres(data_dir)

Boot (or join) the embedded cluster and make the erudi DB ready.

Idempotent: safe to call on an already-initialized data dir or while the cluster is already running (pgserver refcounts users of the data dir).

Every failure below -- the postmaster that never came up, an admin connection refused, a database or an extension that could not be created -- leaves with the postmaster's own last lines attached (:func:_attach_postmaster_log), because the reason is in the server's log and nowhere else.

Source code in backend/src/launcher/postgres_runtime.py
def start_postgres(data_dir: Path | str) -> PostgresHandle:
    """Boot (or join) the embedded cluster and make the `erudi` DB ready.

    Idempotent: safe to call on an already-initialized data dir or while the
    cluster is already running (pgserver refcounts users of the data dir).

    Every failure below -- the postmaster that never came up, an admin
    connection refused, a database or an extension that could not be created
    -- leaves with the postmaster's own last lines attached
    (:func:`_attach_postmaster_log`), because the reason is in the server's
    log and nowhere else.
    """
    data_dir = Path(data_dir)
    try:
        data_dir.mkdir(parents=True, exist_ok=True)
        _prune_stale_handle_pids(data_dir)
        _recover_corrupt_pgdata(data_dir)

        server = _get_server_with_recovery(data_dir)
        # After initdb (the secret file must not pre-exist in PGDATA) and before
        # any other connection: the URLs handed out below all carry the password.
        password = _ensure_cluster_password(data_dir)
        admin_uri = _uri_with_password(server.get_uri(), password)
        _enforce_password_auth(admin_uri, data_dir, password)

        # CREATE DATABASE has no IF NOT EXISTS → guard on pg_database.
        # DB_NAME is an internal constant, never user input.
        with psycopg.connect(admin_uri, autocommit=True) as conn:
            exists = conn.execute(
                "SELECT 1 FROM pg_database WHERE datname = %s", (DB_NAME,)
            ).fetchone()
            if not exists:
                conn.execute(f'CREATE DATABASE "{DB_NAME}"')

        psycopg_url = _uri_for_db(admin_uri, DB_NAME)

        # pgvector extensions are per-database → create inside `erudi`, not the
        # admin DB probed above.
        with psycopg.connect(psycopg_url, autocommit=True) as conn:
            conn.execute("CREATE EXTENSION IF NOT EXISTS vector")
    except BaseException as exc:
        _attach_postmaster_log(exc, data_dir)
        raise

    sqlalchemy_url = psycopg_url.replace("postgresql://", "postgresql+psycopg://", 1)
    logger.info(f"Embedded PostgreSQL ready (data_dir={data_dir})")
    return PostgresHandle(
        server=server,
        data_dir=data_dir,
        psycopg_url=psycopg_url,
        sqlalchemy_url=sqlalchemy_url,
    )

stop_postgres(handle)

Stop the embedded cluster explicitly (deterministic shutdown order).

Source code in backend/src/launcher/postgres_runtime.py
def stop_postgres(handle: PostgresHandle) -> None:
    """Stop the embedded cluster explicitly (deterministic shutdown order)."""
    # Announced before the call: pgserver's cleanup() stops the postmaster
    # (pg_ctl stop, then a kill), and a shutdown that hangs or throws there
    # would otherwise leave the log ending on the last thing the app did.
    logger.info(f"Stopping the embedded PostgreSQL cluster (data_dir={handle.data_dir})")
    handle.server.cleanup()
    logger.info("Embedded PostgreSQL stopped")

src.launcher.runtime_paths

Runtime path management for launcher and backend modules.

This module centralizes the logic that determines where the Erudi backend should read and write its runtime artifacts (embedded PostgreSQL data dir, log files, cached models). The launcher initializes this state before FastAPI imports occur, but a development fallback keeps local uvicorn workflows working without the launcher.

ERUDI_DATA_ROOT (optional env var) points the whole instance -- data dir AND log dir -- at an explicit root instead of the default dev/prod layout. It exists for isolated side-by-side instances (integration tests booting a throwaway backend, QA runs next to a live app) that must not share the default embedded-Postgres cluster or append to the same log files.

RuntimePaths(mode, backend_root, data_dir, log_dir) dataclass

Resolved directories for the current Erudi process.

ensure_runtime_paths_initialized(backend_root=None)

Ensure runtime paths are initialized, defaulting to development mode.

Parameters:

Name Type Description Default
backend_root Optional[Path]

Explicit backend root directory. When omitted, defaults to the repository layout (backend/).

None

Returns:

Name Type Description
RuntimePaths RuntimePaths

Resolved runtime directories.

Source code in backend/src/launcher/runtime_paths.py
def ensure_runtime_paths_initialized(backend_root: Optional[Path] = None) -> RuntimePaths:
    """Ensure runtime paths are initialized, defaulting to development mode.

    Args:
        backend_root: Explicit backend root directory. When omitted, defaults to
            the repository layout (``backend/``).

    Returns:
        RuntimePaths: Resolved runtime directories.
    """
    global _RUNTIME_PATHS
    if _RUNTIME_PATHS is None:
        root = backend_root or Path(__file__).resolve().parents[2]
        packaged_data = root / "data"
        _RUNTIME_PATHS = _compute_runtime_paths(
            mode="dev", backend_root=root, packaged_data_dir=packaged_data
        )
    return _RUNTIME_PATHS

get_runtime_paths()

Return the current runtime paths.

Returns:

Name Type Description
RuntimePaths RuntimePaths

Current runtime path configuration.

Raises:

Type Description
RuntimeError

If runtime paths were not initialized yet.

Source code in backend/src/launcher/runtime_paths.py
def get_runtime_paths() -> RuntimePaths:
    """Return the current runtime paths.

    Returns:
        RuntimePaths: Current runtime path configuration.

    Raises:
        RuntimeError: If runtime paths were not initialized yet.
    """
    if _RUNTIME_PATHS is None:
        raise RuntimeError("Runtime paths not initialized")
    return _RUNTIME_PATHS

initialize_runtime_paths(mode, backend_root, packaged_data_dir=None)

Initialize runtime paths for the current process.

Parameters:

Name Type Description Default
mode str

Runtime mode, typically "dev" or "prod".

required
backend_root Path

Path to the backend root directory (contains src).

required
packaged_data_dir Optional[Path]

Optional path to the read-only data payload bundled with the application. Only required for bundled builds.

None

Returns:

Name Type Description
RuntimePaths RuntimePaths

Resolved directory information for the process.

Raises:

Type Description
ValueError

If runtime paths are initialized more than once or the mode is unsupported.

Source code in backend/src/launcher/runtime_paths.py
def initialize_runtime_paths(
    mode: str, backend_root: Path, packaged_data_dir: Optional[Path] = None
) -> RuntimePaths:
    """Initialize runtime paths for the current process.

    Args:
        mode: Runtime mode, typically ``"dev"`` or ``"prod"``.
        backend_root: Path to the backend root directory (contains ``src``).
        packaged_data_dir: Optional path to the read-only data payload bundled
            with the application. Only required for bundled builds.

    Returns:
        RuntimePaths: Resolved directory information for the process.

    Raises:
        ValueError: If runtime paths are initialized more than once or the mode
            is unsupported.
    """
    global _RUNTIME_PATHS
    if _RUNTIME_PATHS is not None:
        raise ValueError("Runtime paths already initialized")

    runtime_paths = _compute_runtime_paths(
        mode=mode, backend_root=backend_root, packaged_data_dir=packaged_data_dir
    )
    _RUNTIME_PATHS = runtime_paths
    return runtime_paths

src.launcher.windows_job

Windows Job Object binding child-process lifetime to this process (#341).

The parent-death watchdog (#224) and the stdin-EOF watcher both detect a dead Electron parent from WITHIN this process and then run the FastAPI lifespan shutdown, which stops the embedded Postgres cluster deterministically. Both depend on this process staying alive long enough to notice and react.

That assumption breaks when the backend itself is torn down at the same time as Electron: recent Electron versions place their spawned child processes (this backend included) inside a Windows Job Object with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, so a hard-killed Electron main process cascades an OS-level TerminateProcess onto this process within milliseconds -- faster than the 0.25s/2s poll intervals of either watchdog. Postgres and llama-server, spawned as OUR children via plain subprocess.Popen (and, for Postgres, deliberately given their own console by the #162 fix so a dead CONSOLE alone never takes them down), are not members of that job and have no mechanism at all tying their lifetime to ours in this scenario -- so they survive orphaned indefinitely, holding the data directory and the port.

The fix mirrors the same trick one level down: create OUR OWN job with KILL_ON_JOB_CLOSE, assign this process to it, and keep the handle open for the life of the process. Every child this process spawns afterwards (Postgres and its ~10 forked helpers, llama-server) automatically joins the same job unless it explicitly requests CREATE_BREAKAWAY_FROM_JOB -- nothing in this codebase does, so no other file needs to change. Windows nests job objects natively (8+/Server 2012+), so this composes cleanly whether or not Electron's own job already contains this process: whenever THIS process's last handle closes -- clean exit, watchdog-triggered shutdown, or an external TerminateProcess -- the kernel tears down every member of our job too, with no Python code required to run at all. This is deliberately independent of (and a safety net under) the graceful stop_postgres() shutdown path: that path still runs first when there's time for it; this one covers the case where there isn't.

No-op on non-Windows platforms and swallowed on any failure: the app must keep working even where job objects are unavailable or restricted (e.g. under some sandboxes) -- it just loses this extra layer of orphan protection.

bind_children_to_this_process()

Create a kill-on-close Job Object and assign this process to it.

Idempotent-ish: safe to call more than once (a second call just creates and leaks a second job doing the same thing), but callers should only call it once, early at startup and before spawning Postgres/llama-server, so every child inherits membership from the start.

Returns True if the job was created and assigned, False if anything about it failed (already logged) -- the caller never needs to branch on this, it exists for tests.

Source code in backend/src/launcher/windows_job.py
def bind_children_to_this_process() -> bool:
    """Create a kill-on-close Job Object and assign this process to it.

    Idempotent-ish: safe to call more than once (a second call just creates
    and leaks a second job doing the same thing), but callers should only call
    it once, early at startup and before spawning Postgres/llama-server, so
    every child inherits membership from the start.

    Returns True if the job was created and assigned, False if anything about
    it failed (already logged) -- the caller never needs to branch on this,
    it exists for tests.
    """
    global _job_handle

    if platform.system() != "Windows":
        return False

    try:
        kernel32 = ctypes.WinDLL("kernel32", use_last_error=True)

        job = kernel32.CreateJobObjectW(None, None)
        if not job:
            logger.warning(
                f"CreateJobObjectW failed (error={ctypes.get_last_error()}); "
                "Postgres/llama-server may survive a hard-killed parent (#341)"
            )
            return False

        info = _JOBOBJECT_EXTENDED_LIMIT_INFORMATION()
        info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE

        ok = kernel32.SetInformationJobObject(
            wintypes.HANDLE(job),
            JobObjectExtendedLimitInformation,
            ctypes.byref(info),
            ctypes.sizeof(info),
        )
        if not ok:
            logger.warning(
                f"SetInformationJobObject failed (error={ctypes.get_last_error()}); "
                "Postgres/llama-server may survive a hard-killed parent (#341)"
            )
            kernel32.CloseHandle(wintypes.HANDLE(job))
            return False

        # GetCurrentProcess() returns a pseudo-handle (-1) valid for this call
        # without needing OpenProcess/PROCESS_SET_QUOTA|PROCESS_TERMINATE rights.
        current_process = kernel32.GetCurrentProcess()
        ok = kernel32.AssignProcessToJobObject(
            wintypes.HANDLE(job), wintypes.HANDLE(current_process)
        )
        if not ok:
            logger.warning(
                f"AssignProcessToJobObject failed (error={ctypes.get_last_error()}); "
                "Postgres/llama-server may survive a hard-killed parent (#341)"
            )
            kernel32.CloseHandle(wintypes.HANDLE(job))
            return False

        _job_handle = job  # keep alive: see module docstring
        logger.info(
            "Windows job object bound: Postgres/llama-server now die with this "
            "process even on a hard kill (#341)"
        )
        return True
    except Exception as exc:
        logger.warning(f"Could not set up the Windows job object (#341): {exc}")
        return False