Skip to content

Commit f81c146

Browse files
committed
fix: poll for cancelled status instead of asserting immediately
Background workers in replay mode start processing very quickly, creating a race between cancel() and the worker picking up the task. Even calling cancel immediately isn't fast enough to guarantee it wins the race. Solution: Poll for 'cancelled' status (similar to test_background_completes) instead of asserting immediately after calling cancel(). This handles the case where the worker has already started processing when cancel() is called. Signed-off-by: Charlie Doern <cdoern@redhat.com>
1 parent 98e3867 commit f81c146

1 file changed

Lines changed: 38 additions & 13 deletions

File tree

tests/integration/responses/test_openai_responses.py

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -672,19 +672,28 @@ def test_cancel_queued_or_in_progress_response(self, openai_client, text_model_i
672672
assert response.status == "queued"
673673
response_id = response.id
674674

675-
# Cancel immediately - in replay mode, if we wait, the background worker
676-
# will pick up the task, fail (no recording), and transition to 'failed'
677-
# before we can cancel it. Cancel immediately to win the race.
678-
# Cancel the response
679-
cancelled = openai_client.responses.cancel(response_id=response_id)
675+
# Cancel immediately - in replay mode, background worker starts very quickly
676+
openai_client.responses.cancel(response_id=response_id)
680677

681-
assert cancelled.id == response_id
682-
assert cancelled.status == "cancelled"
683-
# Note: background field may not be preserved through OpenAI client deserialization
678+
# Poll for cancelled status (background worker may have picked up task)
679+
max_wait = 5
680+
poll_interval = 0.1
681+
elapsed = 0
684682

685-
# Verify the response stays cancelled
686-
retrieved = openai_client.responses.retrieve(response_id=response_id)
687-
assert retrieved.status == "cancelled"
683+
while elapsed < max_wait:
684+
time.sleep(poll_interval)
685+
elapsed += poll_interval
686+
687+
retrieved = openai_client.responses.retrieve(response_id=response_id)
688+
if retrieved.status == "cancelled":
689+
return
690+
691+
# In replay mode, worker may have started processing before cancel completed
692+
assert retrieved.status in ("queued", "in_progress", "cancelled"), (
693+
f"Unexpected status '{retrieved.status}' - expected queued/in_progress/cancelled"
694+
)
695+
696+
pytest.fail(f"Response did not transition to cancelled within {max_wait} seconds")
688697

689698
def test_cancel_already_cancelled_is_idempotent(self, openai_client, text_model_id):
690699
"""Test that cancelling an already-cancelled response is idempotent."""
@@ -698,8 +707,24 @@ def test_cancel_already_cancelled_is_idempotent(self, openai_client, text_model_
698707
)
699708

700709
response_id = response.id
701-
cancelled = openai_client.responses.cancel(response_id=response_id)
702-
assert cancelled.status == "cancelled"
710+
openai_client.responses.cancel(response_id=response_id)
711+
712+
# Poll for cancelled status
713+
max_wait = 5
714+
poll_interval = 0.1
715+
elapsed = 0
716+
717+
while elapsed < max_wait:
718+
time.sleep(poll_interval)
719+
elapsed += poll_interval
720+
721+
retrieved = openai_client.responses.retrieve(response_id=response_id)
722+
if retrieved.status == "cancelled":
723+
break
724+
725+
assert retrieved.status in ("queued", "in_progress", "cancelled"), f"Unexpected status '{retrieved.status}'"
726+
else:
727+
pytest.fail(f"Response did not transition to cancelled within {max_wait} seconds")
703728

704729
# Cancel again - should return same state without error
705730
cancelled_again = openai_client.responses.cancel(response_id=response_id)

0 commit comments

Comments
 (0)