Skip to content

Commit ce0a6e4

Browse files
authored
fix: CI/CD tests sometimes fail if deployment takes longer than default Task timeout (#540)
This PR introduces a `wait_forever` method on Task, and then uses it for Package & Plugin deployments within tests. The hope is that some of the occasional deployment timeout failures can be avoided by simply extending the wait time. (In response to a PR earlier today in which a single failure related to deployment timeouts happened.)
1 parent 655ae07 commit ce0a6e4

3 files changed

Lines changed: 43 additions & 17 deletions

File tree

src/steamship/base/tasks.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ def wait(
244244
----------
245245
max_timeout_s : int
246246
Max timeout in seconds. Default: 180s. After this timeout, an exception will be thrown.
247+
A timeout of -1 is equivalent to no timeout.
247248
retry_delay_s : float
248249
Delay between status checks. Default: 1s.
249250
on_each_refresh : Optional[Callable[[int, float, Task], None]]
@@ -254,7 +255,9 @@ def wait(
254255
"""
255256
t0 = time.perf_counter()
256257
refresh_count = 0
257-
while time.perf_counter() - t0 < max_timeout_s and self.state not in (
258+
while (
259+
(max_timeout_s == -1) or (time.perf_counter() - t0 < max_timeout_s)
260+
) and self.state not in (
258261
TaskState.succeeded,
259262
TaskState.failed,
260263
):
@@ -273,6 +276,29 @@ def wait(
273276
)
274277
return self.output
275278

279+
def wait_until_completed(
280+
self,
281+
retry_delay_s: float = 1,
282+
on_each_refresh: "Optional[Callable[[int, float, Task], None]]" = None,
283+
):
284+
"""Polls and blocks until the task has succeeded or failed. No timeout on waiting is applied.
285+
286+
Parameters
287+
----------
288+
retry_delay_s : float
289+
Delay between status checks. Default: 1s.
290+
on_each_refresh : Optional[Callable[[int, float, Task], None]]
291+
Optional call back you can get after each refresh is made, including success state refreshes.
292+
The signature represents: (refresh #, total elapsed time, task)
293+
294+
WARNING: Do not pass a long-running function to this variable. It will block the update polling.
295+
"""
296+
return self.wait(
297+
max_timeout_s=-1, # Indicates to not apply a timeout
298+
retry_delay_s=retry_delay_s,
299+
on_each_refresh=on_each_refresh,
300+
)
301+
276302
def refresh(self):
277303
if self.task_id is None:
278304
raise SteamshipError(message="Unable to refresh task because `task_id` is None")

src/steamship/data/package/package_version.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from __future__ import annotations
22

33
import json
4-
from typing import Any, Dict, Type
4+
from typing import Any, Dict, Optional, Type
55

66
from pydantic import BaseModel, Field
77

@@ -35,12 +35,12 @@ def parse_obj(cls: Type[BaseModel], obj: Any) -> BaseModel:
3535
@staticmethod
3636
def create(
3737
client: Client,
38-
package_id: str = None,
39-
handle: str = None,
40-
filename: str = None,
41-
filebytes: bytes = None,
42-
config_template: Dict[str, Any] = None,
43-
hosting_handler: str = None,
38+
package_id: Optional[str] = None,
39+
handle: Optional[str] = None,
40+
filename: Optional[str] = None,
41+
filebytes: Optional[bytes] = None,
42+
config_template: Optional[Dict[str, Any]] = None,
43+
hosting_handler: Optional[str] = None,
4444
) -> PackageVersion:
4545

4646
if filename is None and filebytes is None:
@@ -65,7 +65,7 @@ def create(
6565
file=("package.zip", filebytes, "multipart/form-data"),
6666
expect=PackageVersion,
6767
)
68-
task.wait()
68+
task.wait_until_completed()
6969
return task.output
7070

7171
def delete(self) -> PackageVersion:

src/steamship/data/plugin/plugin_version.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,15 @@ def parse_obj(cls: Type[BaseModel], obj: Any) -> BaseModel:
5656
def create(
5757
client: Client,
5858
handle: str,
59-
plugin_id: str = None,
60-
filename: str = None,
61-
filebytes: bytes = None,
59+
plugin_id: Optional[str] = None,
60+
filename: Optional[str] = None,
61+
filebytes: Optional[bytes] = None,
6262
hosting_memory: Optional[HostingMemory] = None,
6363
hosting_timeout: Optional[HostingTimeout] = None,
64-
hosting_handler: str = None,
65-
is_public: bool = None,
66-
is_default: bool = None,
67-
config_template: Dict[str, Any] = None,
64+
hosting_handler: Optional[str] = None,
65+
is_public: Optional[bool] = None,
66+
is_default: Optional[bool] = None,
67+
config_template: Optional[Dict[str, Any]] = None,
6868
) -> PluginVersion:
6969

7070
if filename is None and filebytes is None:
@@ -94,7 +94,7 @@ def create(
9494
expect=PluginVersion,
9595
)
9696

97-
task.wait()
97+
task.wait_until_completed()
9898
return task.output
9999

100100
@staticmethod

0 commit comments

Comments
 (0)