Fix task polling deadlines in async and sync clients
Fixes #1311.
Change
Both clients check task status immediately, including when the interval exceeds the timeout. Subsequent polling uses a monotonic deadline, includes request time in the budget, and caps each sleep to the remaining time. No new poll begins after the deadline.
Terminal states, lookup errors and async cancellation retain their existing behavior. Negative timeouts, nonpositive intervals and non-finite values are rejected before HTTP access. Public signatures and dependencies are unchanged.
Verification
The same 41 native-client regression cases give 32 failures and 9 passes on the pinned develop base, then 41 passes patched. Mocked GraphQL responses and a deterministic clock cover initial checks, request-time accounting, capped sleeps, errors and cancellation.
The full native unit command passed under Python 3.12.13 in independent replay: 2087 passed, 1 expected failure. Formatting, Ruff, ty, mypy, documentation generation and generated-document validation passed.
Earlier local launcher runs hit Python subprocess pre-exec SIGSEGV failures. Their cause remains unresolved; the successful native replay used default paths and no test exclusions. This is not a hosted-CI claim.
Limits
The deadline bounds polling and sleeps, not an already-running request. Existing client transport/retry settings still govern that request. No live Infrahub service, stable-branch backport or cross-version matrix was tested. This targets develop, where the issue was reproduced.
Summary by cubic
Fixes task polling deadlines in both async and sync clients so waits no longer overrun or reject valid conditions.
- Both clients now check task status immediately, even when the polling interval exceeds the timeout; an already-final task is returned instead of raising
TaskNotCompletedError. - Polling uses a monotonic deadline that includes request time in the budget, and each sleep is capped to the remaining time, so no new request starts after the deadline.
- Invalid timing values (negative timeouts, nonpositive or non-finite intervals) are rejected with
ValueErrorbefore any HTTP request. - Terminal states, lookup errors, and async cancellation behave as before; public signatures and dependencies are unchanged.