@@ -2,7 +2,7 @@ import { setTimeout as setTimeoutPromise } from 'timers/promises';
22import { randomUUID } from 'crypto' ;
33import { ExecutionContext } from 'ava' ;
44import { firstValueFrom , Subject } from 'rxjs' ;
5- import { WorkflowFailedError , WorkflowHandle } from '@temporalio/client' ;
5+ import { WorkflowFailedError } from '@temporalio/client' ;
66import * as activity from '@temporalio/activity' ;
77import { msToNumber , tsToMs } from '@temporalio/common/lib/time' ;
88import { TestWorkflowEnvironment } from '@temporalio/testing' ;
@@ -27,6 +27,7 @@ import * as workflows from './workflows';
2727import {
2828 Context ,
2929 createLocalTestEnvironment ,
30+ hasActivityHeartbeat ,
3031 helpers ,
3132 makeTestFunction ,
3233 setActivityPauseState ,
@@ -1449,6 +1450,55 @@ test('Workflow can return root workflow', async (t) => {
14491450 } ) ;
14501451} ) ;
14511452
1453+ export async function heartbeatPauseWorkflowBasic (
1454+ activityId : string ,
1455+ catchErr : boolean
1456+ ) : Promise < ActivityCancellationDetails | undefined > {
1457+ const { heartbeatCancellationDetailsActivity } = workflow . proxyActivities ( {
1458+ startToCloseTimeout : '5s' ,
1459+ activityId,
1460+ retry : {
1461+ maximumAttempts : 1 ,
1462+ } ,
1463+ heartbeatTimeout : '1s' ,
1464+ } ) ;
1465+
1466+ return await heartbeatCancellationDetailsActivity ( catchErr ) ;
1467+ }
1468+
1469+ test ( 'Activity pause returns expected cancellation details' , async ( t ) => {
1470+ const { createWorker, startWorkflow } = helpers ( t ) ;
1471+
1472+ const worker = await createWorker ( {
1473+ activities : {
1474+ heartbeatCancellationDetailsActivity,
1475+ } ,
1476+ } ) ;
1477+
1478+ await worker . runUntil ( async ( ) => {
1479+ const testActivityId = randomUUID ( ) ;
1480+ const handle = await startWorkflow ( heartbeatPauseWorkflowBasic , {
1481+ args : [ testActivityId , true ] ,
1482+ } ) ;
1483+
1484+ // Wait for activity to start heartbeating
1485+ await waitUntil ( async ( ) => hasActivityHeartbeat ( handle , testActivityId , 'heartbeated' ) , 5000 ) ;
1486+ // Now pause the activity
1487+ await setActivityPauseState ( handle , testActivityId , true ) ;
1488+ // Get the result - should contain pause cancellation details
1489+ const result = await handle . result ( ) ;
1490+
1491+ t . deepEqual ( result , {
1492+ cancelRequested : false ,
1493+ notFound : false ,
1494+ paused : true ,
1495+ timedOut : false ,
1496+ workerShutdown : false ,
1497+ reset : false ,
1498+ } ) ;
1499+ } ) ;
1500+ } ) ;
1501+
14521502export const activityStartedQuery = workflow . defineQuery < boolean , [ number ] > ( 'activityStarted' ) ;
14531503export const proceedSignal = workflow . defineSignal < [ ] > ( 'proceed' ) ;
14541504
@@ -1487,79 +1537,24 @@ export async function heartbeatPauseWorkflow(
14871537 proceed = true ;
14881538 } ) ;
14891539
1490- activity1Started = true ;
14911540 const promise1 = heartbeatCancellationDetailsActivity ( catchErr ) ;
1541+ activity1Started = true ;
14921542
14931543 // Wait for the test to pause activity 1 and signal us to continue
14941544 await workflow . condition ( ( ) => proceed ) ;
14951545 proceed = false ; // reset for next step
14961546
1497- activity2Started = true ;
14981547 const promise2 = heartbeatCancellationDetailsActivity2 ( catchErr ) ;
1548+ activity2Started = true ;
14991549
15001550 // Wait for the test to pause activity 2 and signal us to continue
15011551 await workflow . condition ( ( ) => proceed ) ;
15021552
15031553 return Promise . all ( [ promise1 , promise2 ] ) ;
15041554}
15051555
1506- test ( 'Activity pause returns expected cancellation details' , async ( t ) => {
1507- const { createWorker, startWorkflow } = helpers ( t ) ;
1508- const worker = await createWorker ( {
1509- activities : {
1510- heartbeatCancellationDetailsActivity,
1511- heartbeatCancellationDetailsActivity2 : heartbeatCancellationDetailsActivity ,
1512- } ,
1513- } ) ;
1514-
1515- await worker . runUntil ( async ( ) => {
1516- const testActivityId = randomUUID ( ) ;
1517- const handle = await startWorkflow ( heartbeatPauseWorkflow , { args : [ testActivityId , true , 1 ] } ) ;
1518-
1519- await waitUntil ( async ( ) => handle . query ( activityStartedQuery , 1 ) , 5000 ) ;
1520- await setActivityPauseState ( handle , testActivityId , true ) ;
1521- await handle . signal ( proceedSignal ) ;
1522-
1523- await waitUntil ( async ( ) => handle . query ( activityStartedQuery , 2 ) , 5000 ) ;
1524- await setActivityPauseState ( handle , `${ testActivityId } -2` , true ) ;
1525- await handle . signal ( proceedSignal ) ;
1526-
1527- const result = await handle . result ( ) ;
1528- t . deepEqual ( result [ 0 ] , {
1529- cancelRequested : false ,
1530- notFound : false ,
1531- paused : true ,
1532- timedOut : false ,
1533- workerShutdown : false ,
1534- reset : false ,
1535- } ) ;
1536- t . deepEqual ( result [ 1 ] , {
1537- cancelRequested : false ,
1538- notFound : false ,
1539- paused : true ,
1540- timedOut : false ,
1541- workerShutdown : false ,
1542- reset : false ,
1543- } ) ;
1544- } ) ;
1545- } ) ;
1546-
15471556test ( 'Activity can pause and unpause' , async ( t ) => {
15481557 const { createWorker, startWorkflow } = helpers ( t ) ;
1549- async function checkHeartbeatDetailsExist ( handle : WorkflowHandle , activityId : string ) : Promise < boolean > {
1550- const { raw } = await handle . describe ( ) ;
1551- const activityInfo = raw . pendingActivities ?. find ( ( act ) => act . activityId === activityId ) ;
1552- if ( ! activityInfo ) return false ;
1553-
1554- if ( activityInfo . heartbeatDetails ?. payloads ) {
1555- for ( const payload of activityInfo . heartbeatDetails . payloads ) {
1556- if ( payload . data && payload . data . length > 0 ) {
1557- return true ;
1558- }
1559- }
1560- }
1561- return false ;
1562- }
15631558
15641559 const worker = await createWorker ( {
15651560 activities : {
@@ -1574,13 +1569,13 @@ test('Activity can pause and unpause', async (t) => {
15741569
15751570 await waitUntil ( async ( ) => handle . query ( activityStartedQuery , 1 ) , 5000 ) ;
15761571 await setActivityPauseState ( handle , testActivityId , true ) ;
1577- await waitUntil ( async ( ) => checkHeartbeatDetailsExist ( handle , testActivityId ) , 5000 ) ;
1572+ await waitUntil ( async ( ) => hasActivityHeartbeat ( handle , testActivityId , 'finally-complete' ) , 5000 ) ;
15781573 await setActivityPauseState ( handle , testActivityId , false ) ;
15791574 await handle . signal ( proceedSignal ) ;
15801575
15811576 await waitUntil ( async ( ) => handle . query ( activityStartedQuery , 2 ) , 5000 ) ;
15821577 await setActivityPauseState ( handle , `${ testActivityId } -2` , true ) ;
1583- await waitUntil ( async ( ) => checkHeartbeatDetailsExist ( handle , `${ testActivityId } -2` ) , 5000 ) ;
1578+ await waitUntil ( async ( ) => hasActivityHeartbeat ( handle , `${ testActivityId } -2` , 'finally-complete' ) , 5000 ) ;
15841579 await setActivityPauseState ( handle , `${ testActivityId } -2` , false ) ;
15851580 await handle . signal ( proceedSignal ) ;
15861581
0 commit comments