Skip to content

Commit 2b58a2b

Browse files
authored
fix: fetch the Actor from the API root in get_streamed_log() on last_run() clients (#1143)
`get_streamed_log()` and `get_status_message_watcher()` built the Actor client from the run client's `_base_url`. On `actor(...).last_run()` or `task(...).last_run()` that is the parent's URL, so the Actor lookup hit `/v2/acts/<X>/acts/<actId>`, got a 404, and the logger name had no Actor name. They now use the API root, like `iterate_dataset_items()`. Closes: #1137 *✍️ Drafted by Claude Code*
1 parent b78e4cc commit 2b58a2b

2 files changed

Lines changed: 65 additions & 4 deletions

File tree

‎src/apify_client/_resource_clients/run.py‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ def get_streamed_log(
370370
if actor_id:
371371
actor_client = self._client_registry.actor_client(
372372
resource_id=actor_id,
373-
base_url=self._base_url,
373+
base_url=self._api_base_url,
374374
public_base_url=self._public_base_url,
375375
http_client=self._http_client,
376376
client_registry=self._client_registry,
@@ -458,7 +458,7 @@ def get_status_message_watcher(
458458
if actor_id:
459459
actor_client = self._client_registry.actor_client(
460460
resource_id=actor_id,
461-
base_url=self._base_url,
461+
base_url=self._api_base_url,
462462
public_base_url=self._public_base_url,
463463
http_client=self._http_client,
464464
client_registry=self._client_registry,
@@ -920,7 +920,7 @@ async def get_streamed_log(
920920
if actor_id:
921921
actor_client = self._client_registry.actor_client(
922922
resource_id=actor_id,
923-
base_url=self._base_url,
923+
base_url=self._api_base_url,
924924
public_base_url=self._public_base_url,
925925
http_client=self._http_client,
926926
client_registry=self._client_registry,
@@ -1009,7 +1009,7 @@ async def get_status_message_watcher(
10091009
if actor_id:
10101010
actor_client = self._client_registry.actor_client(
10111011
resource_id=actor_id,
1012-
base_url=self._base_url,
1012+
base_url=self._api_base_url,
10131013
public_base_url=self._public_base_url,
10141014
http_client=self._http_client,
10151015
client_registry=self._client_registry,

‎tests/unit/test_logging.py‎

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,67 @@ def test_redirect_status_message_sync(
562562
assert caplog.records[2].message == 'Status: SUCCEEDED, Message: Final message'
563563

564564

565+
LAST_RUN_PARENTS = (
566+
pytest.param('actor', 'actors', id='actor last run'),
567+
pytest.param('task', 'actor-tasks', id='task last run'),
568+
)
569+
570+
LOGGING_HELPERS = (
571+
pytest.param('get_streamed_log', id='streamed log'),
572+
pytest.param('get_status_message_watcher', id='status message watcher'),
573+
)
574+
575+
576+
def mock_last_run(httpserver: HTTPServer, parent_path: str) -> None:
577+
"""Serve the mocked run at `runs/last` of the parent with ID `parent_id`."""
578+
run_data = StatusResponseGenerator()._create_minimal_run_data('Initial message', 'RUNNING', is_terminal=False)
579+
httpserver.expect_request(f'/v2/{parent_path}/parent_id/runs/last', method='GET').respond_with_json(
580+
{'data': run_data}
581+
)
582+
583+
584+
@pytest.mark.parametrize(('parent_method', 'parent_path'), LAST_RUN_PARENTS)
585+
@pytest.mark.parametrize('helper_method', LOGGING_HELPERS)
586+
@pytest.mark.usefixtures('mock_api')
587+
def test_last_run_logger_name_includes_actor_name_sync(
588+
*,
589+
httpserver: HTTPServer,
590+
parent_method: str,
591+
parent_path: str,
592+
helper_method: str,
593+
) -> None:
594+
"""A `last_run()` client fetches the Actor from the API root and puts its name in the logger name."""
595+
mock_last_run(httpserver, parent_path)
596+
api_url = httpserver.url_for('/').removesuffix('/')
597+
client = ApifyClient(token='mocked_token', api_url=api_url)
598+
run_client = getattr(client, parent_method)('parent_id').last_run()
599+
600+
redirector = getattr(run_client, helper_method)()
601+
602+
assert redirector._to_logger.name == f'apify.{_MOCKED_ACTOR_NAME} runId:{_MOCKED_RUN_ID}'
603+
604+
605+
@pytest.mark.parametrize(('parent_method', 'parent_path'), LAST_RUN_PARENTS)
606+
@pytest.mark.parametrize('helper_method', LOGGING_HELPERS)
607+
@pytest.mark.usefixtures('mock_api')
608+
async def test_last_run_logger_name_includes_actor_name_async(
609+
*,
610+
httpserver: HTTPServer,
611+
parent_method: str,
612+
parent_path: str,
613+
helper_method: str,
614+
) -> None:
615+
"""A `last_run()` client fetches the Actor from the API root and puts its name in the logger name."""
616+
mock_last_run(httpserver, parent_path)
617+
api_url = httpserver.url_for('/').removesuffix('/')
618+
client = ApifyClientAsync(token='mocked_token', api_url=api_url)
619+
run_client = getattr(client, parent_method)('parent_id').last_run()
620+
621+
redirector = await getattr(run_client, helper_method)()
622+
623+
assert redirector._to_logger.name == f'apify.{_MOCKED_ACTOR_NAME} runId:{_MOCKED_RUN_ID}'
624+
625+
565626
async def test_streamed_log_async_restart_after_normal_completion(httpserver: HTTPServer) -> None:
566627
"""Test that StreamedLogAsync cannot be restarted after task completes normally."""
567628
# Set up a quick-completing stream endpoint

0 commit comments

Comments
 (0)