From f7f9788e29048f01397b32451ea5235746ad488f Mon Sep 17 00:00:00 2001 From: Pigbibi <20649888+Pigbibi@users.noreply.github.com> Date: Tue, 21 Apr 2026 04:54:15 +0800 Subject: [PATCH] Harden IB Gateway readiness check --- Dockerfile | 2 +- scripts/wait_for_ib_gateway_ready.sh | 25 +++++++++++++++++++++++++ tests/test_docker_compose_ports.sh | 3 +++ tests/test_wait_for_ib_gateway_ready.sh | 3 +++ 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 8d549ff..c4325a9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ FROM gnzsnz/ib-gateway:latest USER root RUN apt-get update && \ apt-get install -y --no-install-recommends python3-pip xdotool && \ - pip3 install pyotp --break-system-packages && \ + pip3 install pyotp ib_insync --break-system-packages && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* diff --git a/scripts/wait_for_ib_gateway_ready.sh b/scripts/wait_for_ib_gateway_ready.sh index f8e7d55..91567fa 100644 --- a/scripts/wait_for_ib_gateway_ready.sh +++ b/scripts/wait_for_ib_gateway_ready.sh @@ -42,6 +42,31 @@ timeout_seconds = float(os.environ["IB_GATEWAY_HEALTHCHECK_TIMEOUT_SECONDS"]) deadline = time.monotonic() + timeout_seconds +try: + from ib_insync import IB +except ImportError: + IB = None + + +if IB is not None: + ib = IB() + try: + ib.connect(host, port, clientId=client_id, timeout=timeout_seconds) + accounts = ib.managedAccounts() + if not accounts: + raise RuntimeError("IB API healthcheck did not receive managed accounts") + print( + "IB API ib_insync healthcheck ready: " + f"server_version={ib.client.serverVersion()} " + f"client_id={client_id} " + f"accounts={','.join(accounts)}" + ) + finally: + if ib.isConnected(): + ib.disconnect() + raise SystemExit(0) + + def remaining_timeout() -> float: remaining = deadline - time.monotonic() if remaining <= 0: diff --git a/tests/test_docker_compose_ports.sh b/tests/test_docker_compose_ports.sh index 6cbcfab..c11b6d1 100644 --- a/tests/test_docker_compose_ports.sh +++ b/tests/test_docker_compose_ports.sh @@ -3,6 +3,9 @@ set -euo pipefail repo_dir="$(cd "$(dirname "$0")/.." && pwd)" compose_file="$repo_dir/docker-compose.yml" +dockerfile="$repo_dir/Dockerfile" + +grep -Fq 'pip3 install pyotp ib_insync --break-system-packages' "$dockerfile" grep -Fq ' - "4001:4003"' "$compose_file" grep -Fq ' - "4002:4004"' "$compose_file" diff --git a/tests/test_wait_for_ib_gateway_ready.sh b/tests/test_wait_for_ib_gateway_ready.sh index 2a17c3b..e5d015f 100644 --- a/tests/test_wait_for_ib_gateway_ready.sh +++ b/tests/test_wait_for_ib_gateway_ready.sh @@ -13,6 +13,9 @@ grep -Fq 'gateway_port=4001' "$script_file" grep -Fq "docker inspect --format '{{.State.Running}}'" "$script_file" grep -Fq 'IB_GATEWAY_HEALTHCHECK_CLIENT_ID:-999' "$script_file" grep -Fq 'check_api_handshake()' "$script_file" +grep -Fq 'from ib_insync import IB' "$script_file" +grep -Fq 'ib.connect(host, port, clientId=client_id, timeout=timeout_seconds)' "$script_file" +grep -Fq 'IB API ib_insync healthcheck ready' "$script_file" grep -Fq 'b"API\0" + struct.pack(">I", len(b"v157..176")) + b"v157..176"' "$script_file" grep -Fq 'has_next_valid_id and has_managed_accounts' "$script_file" grep -Fq 'IB API handshake readiness' "$script_file"