From 75bcc8d915f497c445dd6c2235aaa29f89178637 Mon Sep 17 00:00:00 2001 From: Jeffrey Wall <265409180+jeffwall-curlewlabs@users.noreply.github.com> Date: Tue, 13 Oct 2026 19:10:37 -0700 Subject: [PATCH] Bound each gh attempt at 30s, so a failing call ends as soon as before 0.2.3 doubled a busy call's attempts, to eight, and each can still run to GH_TIMEOUT_SECONDS. With that at 60s, a call whose every attempt stalls took 8 x 60 + 45 = 525s to fail, against 325s in 0.2.2, and a workflow that sized its slot or record job's timeout-minutes around one failing call could now see the job cancelled at its cap instead of failing with a message. At 30s the same call fails in 8 x 30 + 45 = 285s, or about 345s with a rate-limited answer and its 60s wait, back near 0.2.2's figure, so a cap sized for 0.2.2 holds again. A healthy call has room: GitHub ends any request that takes it more than 10 seconds to process, and these calls are single requests or a page or two. The live job's cap goes back to the 20 minutes it had before 0.2.3, which holds two such calls with room to spare. The version goes to 0.2.4. --- .github/workflows/ci.yml | 2 +- README.md | 2 +- pyproject.toml | 2 +- src/github_cron_trigger/github.py | 8 +++++++- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a058df4..fcf23cb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -89,7 +89,7 @@ jobs: # for the check and again for its cleanup, so an API outage ends in a failed # step with its message rather than a job cancelled at the cap. The healthy # path takes seconds. - timeout-minutes: 25 + timeout-minutes: 20 steps: - uses: actions/checkout@v7.0.1 diff --git a/README.md b/README.md index c2c4590..a137a61 100644 --- a/README.md +++ b/README.md @@ -362,7 +362,7 @@ Any host that can reach `api.github.com` will do, and more than one is better. Install a release, which puts `github-cron-trigger` on PATH: ```sh -pip install "github-cron-trigger @ git+https://github.com/curlewlabs-com/github-cron-trigger@v0.2.3" +pip install "github-cron-trigger @ git+https://github.com/curlewlabs-com/github-cron-trigger@v0.2.4" ``` Or check out a release tag and run it as `PYTHONPATH=src python3 -m diff --git a/pyproject.toml b/pyproject.toml index 4e34102..1a71b07 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "flit_core.buildapi" [project] name = "github-cron-trigger" -version = "0.2.3" +version = "0.2.4" description = "Run each scheduled slot of a GitHub Actions workflow on time and exactly once, with GitHub's schedule as the backstop." readme = "README.md" license = "MIT" diff --git a/src/github_cron_trigger/github.py b/src/github_cron_trigger/github.py index f0eb0e3..2756420 100644 --- a/src/github_cron_trigger/github.py +++ b/src/github_cron_trigger/github.py @@ -13,7 +13,13 @@ # Bound on every `gh` call, so a stalled socket cannot hold a workflow step or an # unattended clock tick open until an outer timeout kills it without a report. -GH_TIMEOUT_SECONDS = 60 +# GitHub ends any request that takes it more than 10 seconds to process, and +# these calls are single requests or a page or two, so a healthy call finishes +# well inside this. It is spent once per attempt, which makes it the larger part +# of how long a failing call can take; a caller sizing a job timeout around a +# call counts every attempt RETRY_DELAYS_SECONDS and RATE_LIMIT_DELAY_SECONDS +# allow. +GH_TIMEOUT_SECONDS = 30 # Waits between attempts on a busy or unreachable API, one attempt per entry # plus a final one. Most such failures are a single lost answer that the next