|
23 | 23 | from ...lib.polling_async import async_poll_until |
24 | 24 | from ...types.devbox_execution_detail_view import DevboxExecutionDetailView |
25 | 25 | from ...types.devbox_async_execution_detail_view import DevboxAsyncExecutionDetailView |
| 26 | +from ..._exceptions import APIStatusError |
26 | 27 |
|
27 | 28 | __all__ = ["ExecutionsResource", "AsyncExecutionsResource"] |
28 | 29 |
|
@@ -121,20 +122,37 @@ def await_completed( |
121 | 122 | Raises: |
122 | 123 | PollingTimeout: If polling times out before execution completes |
123 | 124 | """ |
124 | | - def retrieve_execution() -> DevboxAsyncExecutionDetailView: |
125 | | - return self.retrieve( |
126 | | - execution_id, |
127 | | - devbox_id=devbox_id, |
128 | | - extra_headers=extra_headers, |
129 | | - extra_query=extra_query, |
130 | | - extra_body=extra_body, |
131 | | - timeout=timeout |
| 125 | + |
| 126 | + def wait_for_execution_status() -> DevboxAsyncExecutionDetailView: |
| 127 | + # This wait_for_status endpoint polls the execution status for 60 seconds until it reaches either completed. |
| 128 | + return self._post( |
| 129 | + f"/v1/devboxes/{devbox_id}/executions/{execution_id}/wait_for_status", |
| 130 | + body={"statuses": ["completed"]}, |
| 131 | + options=make_request_options( |
| 132 | + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout |
| 133 | + ), |
| 134 | + cast_to=DevboxAsyncExecutionDetailView, |
132 | 135 | ) |
| 136 | + |
| 137 | + def handle_timeout_error(error: Exception) -> DevboxAsyncExecutionDetailView: |
| 138 | + # Handle 408 timeout errors by returning current execution state to continue polling |
| 139 | + if isinstance(error, APIStatusError) and error.response.status_code == 408: |
| 140 | + # Return a placeholder result to continue polling |
| 141 | + return DevboxAsyncExecutionDetailView( |
| 142 | + devbox_id=devbox_id, |
| 143 | + execution_id=execution_id, |
| 144 | + status="queued", |
| 145 | + stdout="", |
| 146 | + stderr="", |
| 147 | + ) |
| 148 | + else: |
| 149 | + # Re-raise other errors to stop polling |
| 150 | + raise error |
133 | 151 |
|
134 | 152 | def is_done(execution: DevboxAsyncExecutionDetailView) -> bool: |
135 | 153 | return execution.status == 'completed' |
136 | 154 |
|
137 | | - return poll_until(retrieve_execution, is_done, config) |
| 155 | + return poll_until(wait_for_execution_status, is_done, config, handle_timeout_error) |
138 | 156 |
|
139 | 157 | def execute_async( |
140 | 158 | self, |
@@ -397,20 +415,34 @@ async def await_completed( |
397 | 415 | Raises: |
398 | 416 | PollingTimeout: If polling times out before execution completes |
399 | 417 | """ |
400 | | - async def retrieve_execution() -> DevboxAsyncExecutionDetailView: |
401 | | - return await self.retrieve( |
402 | | - execution_id, |
403 | | - devbox_id=devbox_id, |
404 | | - extra_headers=extra_headers, |
405 | | - extra_query=extra_query, |
406 | | - extra_body=extra_body, |
407 | | - timeout=timeout, |
408 | | - ) |
| 418 | + async def wait_for_execution_status() -> DevboxAsyncExecutionDetailView: |
| 419 | + try: |
| 420 | + return await self._post( |
| 421 | + f"/v1/devboxes/{devbox_id}/executions/{execution_id}/wait_for_status", |
| 422 | + body={"statuses": ["completed"]}, |
| 423 | + options=make_request_options( |
| 424 | + extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout |
| 425 | + ), |
| 426 | + cast_to=DevboxAsyncExecutionDetailView, |
| 427 | + ) |
| 428 | + except APIStatusError as error: |
| 429 | + if error.response.status_code == 408: |
| 430 | + # Handle 408 timeout errors by returning current execution state to continue polling |
| 431 | + return DevboxAsyncExecutionDetailView( |
| 432 | + devbox_id=devbox_id, |
| 433 | + execution_id=execution_id, |
| 434 | + status="queued", |
| 435 | + stdout="", |
| 436 | + stderr="", |
| 437 | + ) |
| 438 | + else: |
| 439 | + # Re-raise other errors to stop polling |
| 440 | + raise |
409 | 441 |
|
410 | 442 | def is_done(execution: DevboxAsyncExecutionDetailView) -> bool: |
411 | 443 | return execution.status == 'completed' |
412 | | - |
413 | | - return await async_poll_until(retrieve_execution, is_done, polling_config) |
| 444 | + |
| 445 | + return await async_poll_until(wait_for_execution_status, is_done, polling_config) |
414 | 446 |
|
415 | 447 | async def execute_async( |
416 | 448 | self, |
|
0 commit comments