@@ -2,7 +2,7 @@ import { setTimeout as setTimeoutPromise } from 'timers/promises';
2
2
import { randomUUID } from 'crypto' ;
3
3
import { ExecutionContext } from 'ava' ;
4
4
import { firstValueFrom , Subject } from 'rxjs' ;
5
- import { WorkflowFailedError , WorkflowHandle } from '@temporalio/client' ;
5
+ import { WorkflowFailedError } from '@temporalio/client' ;
6
6
import * as activity from '@temporalio/activity' ;
7
7
import { msToNumber , tsToMs } from '@temporalio/common/lib/time' ;
8
8
import { TestWorkflowEnvironment } from '@temporalio/testing' ;
@@ -27,6 +27,7 @@ import * as workflows from './workflows';
27
27
import {
28
28
Context ,
29
29
createLocalTestEnvironment ,
30
+ hasActivityHeartbeat ,
30
31
helpers ,
31
32
makeTestFunction ,
32
33
setActivityPauseState ,
@@ -1449,6 +1450,55 @@ test('Workflow can return root workflow', async (t) => {
1449
1450
} ) ;
1450
1451
} ) ;
1451
1452
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
+
1452
1502
export const activityStartedQuery = workflow . defineQuery < boolean , [ number ] > ( 'activityStarted' ) ;
1453
1503
export const proceedSignal = workflow . defineSignal < [ ] > ( 'proceed' ) ;
1454
1504
@@ -1487,79 +1537,24 @@ export async function heartbeatPauseWorkflow(
1487
1537
proceed = true ;
1488
1538
} ) ;
1489
1539
1490
- activity1Started = true ;
1491
1540
const promise1 = heartbeatCancellationDetailsActivity ( catchErr ) ;
1541
+ activity1Started = true ;
1492
1542
1493
1543
// Wait for the test to pause activity 1 and signal us to continue
1494
1544
await workflow . condition ( ( ) => proceed ) ;
1495
1545
proceed = false ; // reset for next step
1496
1546
1497
- activity2Started = true ;
1498
1547
const promise2 = heartbeatCancellationDetailsActivity2 ( catchErr ) ;
1548
+ activity2Started = true ;
1499
1549
1500
1550
// Wait for the test to pause activity 2 and signal us to continue
1501
1551
await workflow . condition ( ( ) => proceed ) ;
1502
1552
1503
1553
return Promise . all ( [ promise1 , promise2 ] ) ;
1504
1554
}
1505
1555
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
-
1547
1556
test ( 'Activity can pause and unpause' , async ( t ) => {
1548
1557
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
- }
1563
1558
1564
1559
const worker = await createWorker ( {
1565
1560
activities : {
@@ -1574,13 +1569,13 @@ test('Activity can pause and unpause', async (t) => {
1574
1569
1575
1570
await waitUntil ( async ( ) => handle . query ( activityStartedQuery , 1 ) , 5000 ) ;
1576
1571
await setActivityPauseState ( handle , testActivityId , true ) ;
1577
- await waitUntil ( async ( ) => checkHeartbeatDetailsExist ( handle , testActivityId ) , 5000 ) ;
1572
+ await waitUntil ( async ( ) => hasActivityHeartbeat ( handle , testActivityId , 'finally-complete' ) , 5000 ) ;
1578
1573
await setActivityPauseState ( handle , testActivityId , false ) ;
1579
1574
await handle . signal ( proceedSignal ) ;
1580
1575
1581
1576
await waitUntil ( async ( ) => handle . query ( activityStartedQuery , 2 ) , 5000 ) ;
1582
1577
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 ) ;
1584
1579
await setActivityPauseState ( handle , `${ testActivityId } -2` , false ) ;
1585
1580
await handle . signal ( proceedSignal ) ;
1586
1581
0 commit comments