Skip to content

Commit 29c696f

Browse files
committed
added await_suspended methods to base api
1 parent 8c417ce commit 29c696f

1 file changed

Lines changed: 86 additions & 0 deletions

File tree

src/runloop_api_client/resources/devboxes/devboxes.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,50 @@ def is_done_booting(devbox: DevboxView) -> bool:
426426

427427
return devbox
428428

429+
def await_suspended(
430+
self,
431+
id: str,
432+
*,
433+
polling_config: PollingConfig | None = None,
434+
) -> DevboxView:
435+
"""Wait for a devbox to reach the suspended state.
436+
437+
Args:
438+
id: The ID of the devbox to wait for.
439+
polling_config: Optional polling configuration.
440+
441+
Returns:
442+
The devbox in the suspended state.
443+
444+
Raises:
445+
PollingTimeout: If polling times out before the devbox is suspended.
446+
RunloopError: If the devbox enters a non-suspended terminal state.
447+
"""
448+
449+
def wait_for_devbox_status() -> DevboxView:
450+
return self._post(
451+
f"/v1/devboxes/{id}/wait_for_status",
452+
body={"statuses": ["suspended", "failure", "shutdown"]},
453+
cast_to=DevboxView,
454+
)
455+
456+
def handle_timeout_error(error: Exception) -> DevboxView:
457+
if isinstance(error, APITimeoutError) or (
458+
isinstance(error, APIStatusError) and error.response.status_code == 408
459+
):
460+
return placeholder_devbox_view(id)
461+
raise error
462+
463+
def is_terminal_state(devbox: DevboxView) -> bool:
464+
return devbox.status in {"suspended", "failure", "shutdown"}
465+
466+
devbox = poll_until(wait_for_devbox_status, is_terminal_state, polling_config, handle_timeout_error)
467+
468+
if devbox.status != "suspended":
469+
raise RunloopError(f"Devbox entered non-suspended terminal state: {devbox.status}")
470+
471+
return devbox
472+
429473
def create_and_await_running(
430474
self,
431475
*,
@@ -1917,6 +1961,48 @@ def is_done_booting(devbox: DevboxView) -> bool:
19171961

19181962
return devbox
19191963

1964+
async def await_suspended(
1965+
self,
1966+
id: str,
1967+
*,
1968+
polling_config: PollingConfig | None = None,
1969+
) -> DevboxView:
1970+
"""Wait for a devbox to reach the suspended state.
1971+
1972+
Args:
1973+
id: The ID of the devbox to wait for.
1974+
polling_config: Optional polling configuration.
1975+
1976+
Returns:
1977+
The devbox in the suspended state.
1978+
1979+
Raises:
1980+
PollingTimeout: If polling times out before the devbox is suspended.
1981+
RunloopError: If the devbox enters a non-suspended terminal state.
1982+
"""
1983+
1984+
async def wait_for_devbox_status() -> DevboxView:
1985+
try:
1986+
return await self._post(
1987+
f"/v1/devboxes/{id}/wait_for_status",
1988+
body={"statuses": ["suspended", "failure", "shutdown"]},
1989+
cast_to=DevboxView,
1990+
)
1991+
except (APITimeoutError, APIStatusError) as error:
1992+
if isinstance(error, APITimeoutError) or error.response.status_code == 408:
1993+
return placeholder_devbox_view(id)
1994+
raise
1995+
1996+
def is_terminal_state(devbox: DevboxView) -> bool:
1997+
return devbox.status in {"suspended", "failure", "shutdown"}
1998+
1999+
devbox = await async_poll_until(wait_for_devbox_status, is_terminal_state, polling_config)
2000+
2001+
if devbox.status != "suspended":
2002+
raise RunloopError(f"Devbox entered non-suspended terminal state: {devbox.status}")
2003+
2004+
return devbox
2005+
19202006
async def update(
19212007
self,
19222008
id: str,

0 commit comments

Comments
 (0)