@@ -451,3 +451,61 @@ async def activity_fn():
451451 identity = "identity" ,
452452 )
453453 )
454+
455+
456+ async def test_heartbeat_details_recovery_across_attempts (client ):
457+ """Simulate retry: first attempt has no heartbeat details and fails,
458+ second attempt receives heartbeat details from the server and succeeds."""
459+ worker_stub = client .worker_stub
460+ worker_stub .RespondActivityTaskFailed = AsyncMock (
461+ return_value = RespondActivityTaskFailedResponse ()
462+ )
463+ worker_stub .RespondActivityTaskCompleted = AsyncMock (
464+ return_value = RespondActivityTaskCompletedResponse ()
465+ )
466+ worker_stub .RecordActivityTaskHeartbeat = AsyncMock (
467+ return_value = RecordActivityTaskHeartbeatResponse ()
468+ )
469+
470+ attempt_count = 0
471+
472+ reg = Registry ()
473+
474+ @reg .activity (name = "activity_type" )
475+ async def activity_fn ():
476+ nonlocal attempt_count
477+ attempt_count += 1
478+
479+ details = activity .heartbeat_details ()
480+ if not details :
481+ activity .heartbeat ("step1" , 50 )
482+ raise RuntimeError ("simulated failure on first attempt" )
483+
484+ return activity .heartbeat_details (str , int )
485+
486+ executor = ActivityExecutor (client , "task_list" , "identity" , 1 , reg .get_activity )
487+
488+ # First attempt: no heartbeat details, activity heartbeats progress then fails
489+ await executor .execute (fake_task ("activity_type" , "" ))
490+ worker_stub .RespondActivityTaskFailed .assert_called_once ()
491+ worker_stub .RecordActivityTaskHeartbeat .assert_called_once_with (
492+ RecordActivityTaskHeartbeatRequest (
493+ task_token = b"task_token" ,
494+ details = Payload (data = b'"step1" 50' ),
495+ identity = "identity" ,
496+ )
497+ )
498+
499+ # Second attempt: server provides heartbeat details from previous attempt
500+ await executor .execute (
501+ fake_task ("activity_type" , "" , heartbeat_details = '"step1" 50' )
502+ )
503+ worker_stub .RespondActivityTaskCompleted .assert_called_once_with (
504+ RespondActivityTaskCompletedRequest (
505+ task_token = b"task_token" ,
506+ result = Payload (data = b'["step1",50]' ),
507+ identity = "identity" ,
508+ )
509+ )
510+
511+ assert attempt_count == 2
0 commit comments