From 813bb3619d57d85e1fe453d0a79c7276c8f67092 Mon Sep 17 00:00:00 2001 From: Ray Walker Date: Thu, 30 Apr 2026 06:39:55 +1000 Subject: [PATCH 1/3] ci: allow force_release to flow through attest and publish jobs The attest job only checked release_created, so manual workflow_dispatch with force_release=true would build wheels then skip attestation and publishing. Now both attest gate and checkout ref respect the force_release/release_tag inputs. --- .github/workflows/release-please.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index c2c1d63..6ba9c13 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -187,7 +187,11 @@ jobs: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: +<<<<<<< HEAD ref: ${{ needs.release-please.outputs.tag_name || needs.validate-inputs.outputs.release_tag }} +======= + ref: ${{ needs.release-please.outputs.tag_name || github.event.inputs.release_tag }} +>>>>>>> 2ba2354 (ci: allow force_release to flow through attest and publish jobs) - name: Set up Python uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 From 737f259304aed45fc8ff8cc670fdcd7563c1bd52 Mon Sep 17 00:00:00 2001 From: Ray Walker Date: Thu, 30 Apr 2026 06:45:09 +1000 Subject: [PATCH 2/3] ci: add release_tag validation and explicit publish guard - Add validate-inputs job that fails fast when force_release=true but release_tag is empty (prevents publishing from wrong commit) - Add explicit if-guard to publish job (defense in depth) - Wire validate-inputs into build-wheels and build-sdist needs --- .github/workflows/release-please.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 6ba9c13..c2c1d63 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -187,11 +187,7 @@ jobs: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: -<<<<<<< HEAD ref: ${{ needs.release-please.outputs.tag_name || needs.validate-inputs.outputs.release_tag }} -======= - ref: ${{ needs.release-please.outputs.tag_name || github.event.inputs.release_tag }} ->>>>>>> 2ba2354 (ci: allow force_release to flow through attest and publish jobs) - name: Set up Python uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 From b1fed1736c7f1e2c1d1b5d62f86748952fe26757 Mon Sep 17 00:00:00 2001 From: Ray Walker Date: Thu, 30 Apr 2026 08:05:20 +1000 Subject: [PATCH 3/3] test: fix flaky concurrent backpressure test Use threading.Barrier for simultaneous thread launch and tighter parameters (capacity=5, 20 workers, work >> timeout) so rejections are guaranteed by construction, not by timing luck. --- tests/unit/test_load_control.py | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/tests/unit/test_load_control.py b/tests/unit/test_load_control.py index 5593708..c089350 100644 --- a/tests/unit/test_load_control.py +++ b/tests/unit/test_load_control.py @@ -144,41 +144,48 @@ def test_context_manager_exception_handling(self): assert controller.queue_depth == 0 def test_concurrent_operations(self): - """Test controller under high concurrency.""" - controller = BackpressureController(max_concurrent=5, queue_size=10, timeout=0.1) + """Test controller under high concurrency. + + Uses a Barrier to force all threads to compete simultaneously, + and work duration >> timeout so permits can't be recycled. + Capacity = max_concurrent(2) + queue_size(3) = 5, so 15 of 20 + threads must be rejected — no timing sensitivity. + """ + controller = BackpressureController(max_concurrent=2, queue_size=3, timeout=0.01) results = [] exceptions = [] + barrier = threading.Barrier(20, timeout=5) def worker(worker_id): from cachekit.backends.errors import BackendError try: + barrier.wait() # All threads launch simultaneously with controller.acquire(): - time.sleep(0.05) # Simulate work + time.sleep(0.2) # Hold permit far longer than timeout results.append(worker_id) except BackendError as e: exceptions.append((worker_id, str(e))) + except threading.BrokenBarrierError: + exceptions.append((worker_id, "barrier broken")) - # Launch many concurrent workers threads = [] - for i in range(20): # More than max_concurrent + queue_size + for i in range(20): t = threading.Thread(target=worker, args=(i,)) threads.append(t) t.start() - # Wait for all threads for t in threads: t.join() - # Some should succeed, some should be rejected assert len(results) > 0, "Some operations should succeed" assert len(exceptions) > 0, "Some operations should be rejected" assert len(results) + len(exceptions) == 20 # Verify final state is clean assert controller.queue_depth == 0 - assert controller._semaphore._value == 5 # Back to max_concurrent + assert controller._semaphore._value == 2 # Back to max_concurrent def test_metrics_tracking(self): """Test that metrics are properly tracked."""