44import math
55import time
66from datetime import datetime , timezone
7+ from typing import Any , Protocol
78
89from apify_shared .consts import ActorJobStatus
910
2021class ActorJobBaseClient (ResourceClient ):
2122 """Base sub-client class for Actor runs and Actor builds."""
2223
23- def _wait_for_finish (self , wait_secs : int | None = None ) -> dict | None :
24+ def _wait_for_finish (
25+ self , wait_secs : int | None = None , response_watcher : ResponseWatcher | None = None
26+ ) -> dict | None :
2427 started_at = datetime .now (timezone .utc )
2528 should_repeat = True
2629 job : dict | None = None
@@ -39,6 +42,9 @@ def _wait_for_finish(self, wait_secs: int | None = None) -> dict | None:
3942 )
4043 job = parse_date_fields (pluck_data (response .json ()))
4144
45+ if response_watcher :
46+ response_watcher (job )
47+
4248 seconds_elapsed = math .floor ((datetime .now (timezone .utc ) - started_at ).total_seconds ())
4349 if ActorJobStatus (job ['status' ]).is_terminal or (
4450 wait_secs is not None and seconds_elapsed >= wait_secs
@@ -74,7 +80,9 @@ def _abort(self, *, gracefully: bool | None = None) -> dict:
7480class ActorJobBaseClientAsync (ResourceClientAsync ):
7581 """Base async sub-client class for Actor runs and Actor builds."""
7682
77- async def _wait_for_finish (self , wait_secs : int | None = None ) -> dict | None :
83+ async def _wait_for_finish (
84+ self , wait_secs : int | None = None , response_watcher : ResponseWatcher | None = None
85+ ) -> dict | None :
7886 started_at = datetime .now (timezone .utc )
7987 should_repeat = True
8088 job : dict | None = None
@@ -93,6 +101,9 @@ async def _wait_for_finish(self, wait_secs: int | None = None) -> dict | None:
93101 )
94102 job = parse_date_fields (pluck_data (response .json ()))
95103
104+ if response_watcher :
105+ response_watcher (job )
106+
96107 seconds_elapsed = math .floor ((datetime .now (timezone .utc ) - started_at ).total_seconds ())
97108 if ActorJobStatus (job ['status' ]).is_terminal or (
98109 wait_secs is not None and seconds_elapsed >= wait_secs
@@ -123,3 +134,10 @@ async def _abort(self, *, gracefully: bool | None = None) -> dict:
123134 params = self ._params (gracefully = gracefully ),
124135 )
125136 return parse_date_fields (pluck_data (response .json ()))
137+
138+
139+ class ResponseWatcher (Protocol ):
140+ """Protocol for a callable watching parsed responses from wait_for_finish methods."""
141+
142+ def __call__ (self , response : dict [str , Any ] | None ) -> Any :
143+ """Watch the parsed response and act if needed."""
0 commit comments