Skip to content

Commit cd3a240

Browse files
authored
add cancel request (#853)
1 parent bcdcdc8 commit cd3a240

File tree

10 files changed

+108
-29
lines changed

10 files changed

+108
-29
lines changed

src/utils/data-formatters/format-pending-workflow-history-event/__tests__/index.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { ZodError } from 'zod';
33
import logger from '@/utils/logger';
44
import {
55
pendingActivityTaskStartEvent,
6+
pendingActivityTaskStartEventWithCancelRequestedState,
67
pendingActivityTaskStartEventWithStartedState,
78
pendingDecisionTaskStartEvent,
89
pendingDecisionTaskStartEventWithStartedState,
@@ -15,6 +16,7 @@ jest.mock('@/utils/logger');
1516
const pendingEvents = [
1617
pendingActivityTaskStartEvent,
1718
pendingActivityTaskStartEventWithStartedState,
19+
pendingActivityTaskStartEventWithCancelRequestedState,
1820
pendingDecisionTaskStartEvent,
1921
pendingDecisionTaskStartEventWithStartedState,
2022
];

src/utils/data-formatters/format-pending-workflow-history-event/__tests__/index.test.ts.snapshot

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,34 @@ exports[`formatWorkflowHistoryEvent should format workflow pendingActivityTaskSt
5656
}
5757
`;
5858

59+
exports[`formatWorkflowHistoryEvent should format workflow pendingActivityTaskStartEventAttributes to match snapshot 3`] = `
60+
{
61+
"activityId": "0",
62+
"activityType": {
63+
"name": "activity.cron.Start",
64+
},
65+
"attempt": 1,
66+
"eventTime": 2024-09-07T22:16:10.599Z,
67+
"eventType": "PendingActivityTaskStart",
68+
"expirationTime": 1970-01-01T00:06:00.000Z,
69+
"heartbeatDetails": [
70+
"1725747370575409843",
71+
"gadence-canary-xdc",
72+
"workflow.sanity",
73+
],
74+
"lastFailureDetails": null,
75+
"lastFailureReason": "",
76+
"lastHeartbeatTime": null,
77+
"lastStartedTime": 2024-09-07T22:16:10.599Z,
78+
"lastWorkerIdentity": "",
79+
"maximumAttempts": 10,
80+
"scheduleId": 7,
81+
"scheduledTime": 1970-01-01T00:03:00.000Z,
82+
"startedWorkerIdentity": "worker-1",
83+
"state": "cancel requested",
84+
}
85+
`;
86+
5987
exports[`formatWorkflowHistoryEvent should format workflow pendingDecisionTaskStartEventAttributes to match snapshot 1`] = `
6088
{
6189
"attempt": 1,

src/utils/data-formatters/schema/pending-history-event-schema.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export const pendingActivityTaskStartSchema = z.object({
3232
state: z.enum([
3333
PendingActivityState.PENDING_ACTIVITY_STATE_SCHEDULED,
3434
PendingActivityState.PENDING_ACTIVITY_STATE_STARTED,
35+
PendingActivityState.PENDING_ACTIVITY_STATE_CANCEL_REQUESTED,
3536
]),
3637
heartbeatDetails: payloadSchema.nullable(),
3738
lastHeartbeatTime: timestampSchema.nullable(),

src/views/workflow-history/__fixtures__/workflow-history-pending-events.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,14 @@ export const pendingActivityTaskStartEventWithStartedState = {
5454
},
5555
} as const satisfies PendingActivityTaskStartEvent;
5656

57+
export const pendingActivityTaskStartEventWithCancelRequestedState = {
58+
...pendingActivityTaskStartEventWithStartedState,
59+
pendingActivityTaskStartEventAttributes: {
60+
...pendingActivityTaskStartEventWithStartedState.pendingActivityTaskStartEventAttributes,
61+
state: 'PENDING_ACTIVITY_STATE_CANCEL_REQUESTED',
62+
},
63+
} as const satisfies PendingActivityTaskStartEvent;
64+
5765
export const pendingDecisionTaskStartEvent = {
5866
eventId: null,
5967
computedEventId: 'pending-7',

src/views/workflow-history/helpers/__tests__/group-history-events.test.ts

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
} from '../../__fixtures__/workflow-history-decision-events';
1212
import {
1313
pendingActivityTaskStartEvent,
14+
pendingActivityTaskStartEventWithCancelRequestedState,
1415
pendingActivityTaskStartEventWithStartedState,
1516
pendingDecisionTaskStartEvent,
1617
pendingDecisionTaskStartEventWithStartedState,
@@ -149,22 +150,25 @@ describe('groupHistoryEvents', () => {
149150
]);
150151
});
151152

152-
it('should append pending activity start with started state to group that has scheduled activity event only', () => {
153+
it('should append pending activity start with different states to group that has scheduled activity event only', () => {
153154
const events: ActivityHistoryEvent[] = [scheduleActivityTaskEvent];
154-
const pendingStartActivities = [
155+
const testPendingActivities = [
155156
pendingActivityTaskStartEventWithStartedState,
157+
pendingActivityTaskStartEventWithCancelRequestedState,
156158
];
157159
(getHistoryEventGroupId as jest.Mock).mockReturnValue('group1');
158160

159-
const result = groupHistoryEvents(events, {
160-
pendingStartDecision: null,
161-
pendingStartActivities,
162-
});
161+
testPendingActivities.forEach((pendingActivityTaskStart) => {
162+
const result = groupHistoryEvents(events, {
163+
pendingStartDecision: null,
164+
pendingStartActivities: [pendingActivityTaskStart],
165+
});
163166

164-
expect(result.group1.events).toEqual([
165-
...events,
166-
...pendingStartActivities,
167-
]);
167+
expect(result.group1.events).toEqual([
168+
...events,
169+
pendingActivityTaskStart,
170+
]);
171+
});
168172
});
169173

170174
it('should not append pending activity start to group if it does not have scheduled activity event', () => {

src/views/workflow-history/helpers/get-history-group-from-events/__tests__/get-activity-group-from-events.test.ts

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,19 @@ import {
66
startActivityTaskEvent,
77
timeoutActivityTaskEvent,
88
} from '@/views/workflow-history/__fixtures__/workflow-history-activity-events';
9+
import {
10+
pendingActivityTaskStartEvent,
11+
pendingActivityTaskStartEventWithStartedState,
12+
} from '@/views/workflow-history/__fixtures__/workflow-history-pending-events';
913

10-
import type { ActivityHistoryEvent } from '../../../workflow-history.types';
14+
import type { ExtendedActivityHistoryEvent } from '../../../workflow-history.types';
1115
import getActivityGroupFromEvents from '../get-activity-group-from-events';
1216

1317
jest.useFakeTimers().setSystemTime(new Date('2024-05-25'));
1418

1519
describe('getActivityGroupFromEvents', () => {
1620
it('should return a group with a proper label when scheduled event exists', () => {
17-
const events: ActivityHistoryEvent[] = [scheduleActivityTaskEvent];
21+
const events: ExtendedActivityHistoryEvent[] = [scheduleActivityTaskEvent];
1822

1923
const scheduelAttrs =
2024
scheduleActivityTaskEvent.activityTaskScheduledEventAttributes;
@@ -26,21 +30,21 @@ describe('getActivityGroupFromEvents', () => {
2630
});
2731

2832
it('should return a group with empty label when scheduled event is missing', () => {
29-
const completeEvents: ActivityHistoryEvent[] = [
33+
const completeEvents: ExtendedActivityHistoryEvent[] = [
3034
startActivityTaskEvent,
3135
completeActivityTaskEvent,
3236
];
3337
const completedActivitygroup = getActivityGroupFromEvents(completeEvents);
3438
expect(completedActivitygroup.label).toBe('');
3539

36-
const failureEvents: ActivityHistoryEvent[] = [
40+
const failureEvents: ExtendedActivityHistoryEvent[] = [
3741
startActivityTaskEvent,
3842
failedActivityTaskEvent,
3943
];
4044
const failedActivitygroup = getActivityGroupFromEvents(failureEvents);
4145
expect(failedActivitygroup.label).toBe('');
4246

43-
const timeoutEvents: ActivityHistoryEvent[] = [
47+
const timeoutEvents: ExtendedActivityHistoryEvent[] = [
4448
startActivityTaskEvent,
4549
timeoutActivityTaskEvent,
4650
];
@@ -51,7 +55,7 @@ describe('getActivityGroupFromEvents', () => {
5155
it('should return a group with hasMissingEvents when any event is missing', () => {
5256
const assertions: Array<{
5357
name: string;
54-
events: ActivityHistoryEvent[];
58+
events: ExtendedActivityHistoryEvent[];
5559
assertionValue: boolean;
5660
}> = [
5761
{
@@ -92,7 +96,7 @@ describe('getActivityGroupFromEvents', () => {
9296
});
9397

9498
it('should return a group with groupType equal to Activity', () => {
95-
const events: ActivityHistoryEvent[] = [
99+
const events: ExtendedActivityHistoryEvent[] = [
96100
scheduleActivityTaskEvent,
97101
startActivityTaskEvent,
98102
completeActivityTaskEvent,
@@ -102,8 +106,9 @@ describe('getActivityGroupFromEvents', () => {
102106
});
103107

104108
it('should return group eventsMetadata with correct labels', () => {
105-
const events: ActivityHistoryEvent[] = [
109+
const events: ExtendedActivityHistoryEvent[] = [
106110
scheduleActivityTaskEvent,
111+
pendingActivityTaskStartEvent,
107112
startActivityTaskEvent,
108113
completeActivityTaskEvent,
109114
failedActivityTaskEvent,
@@ -113,6 +118,7 @@ describe('getActivityGroupFromEvents', () => {
113118
const group = getActivityGroupFromEvents(events);
114119
expect(group.eventsMetadata.map(({ label }) => label)).toEqual([
115120
'Scheduled',
121+
'Starting',
116122
'Started',
117123
'Completed',
118124
'Failed',
@@ -123,14 +129,16 @@ describe('getActivityGroupFromEvents', () => {
123129

124130
it('should return group eventsMetadata with correct status', () => {
125131
// just scheduled
126-
const scheduleEvents: ActivityHistoryEvent[] = [scheduleActivityTaskEvent];
132+
const scheduleEvents: ExtendedActivityHistoryEvent[] = [
133+
scheduleActivityTaskEvent,
134+
];
127135
const scheduledGroup = getActivityGroupFromEvents(scheduleEvents);
128136
expect(scheduledGroup.eventsMetadata.map(({ status }) => status)).toEqual([
129137
'WAITING',
130138
]);
131139

132140
// started
133-
const startEvents: ActivityHistoryEvent[] = [
141+
const startEvents: ExtendedActivityHistoryEvent[] = [
134142
scheduleActivityTaskEvent,
135143
startActivityTaskEvent,
136144
];
@@ -141,7 +149,7 @@ describe('getActivityGroupFromEvents', () => {
141149
]);
142150

143151
// Completed
144-
const completeEvents: ActivityHistoryEvent[] = [
152+
const completeEvents: ExtendedActivityHistoryEvent[] = [
145153
scheduleActivityTaskEvent,
146154
startActivityTaskEvent,
147155
completeActivityTaskEvent,
@@ -154,7 +162,7 @@ describe('getActivityGroupFromEvents', () => {
154162
]);
155163

156164
// Failed
157-
const failureEvents: ActivityHistoryEvent[] = [
165+
const failureEvents: ExtendedActivityHistoryEvent[] = [
158166
scheduleActivityTaskEvent,
159167
startActivityTaskEvent,
160168
failedActivityTaskEvent,
@@ -167,7 +175,7 @@ describe('getActivityGroupFromEvents', () => {
167175
]);
168176

169177
// Canceled
170-
const cancelEvents: ActivityHistoryEvent[] = [
178+
const cancelEvents: ExtendedActivityHistoryEvent[] = [
171179
scheduleActivityTaskEvent,
172180
startActivityTaskEvent,
173181
cancelActivityTaskEvent,
@@ -180,7 +188,7 @@ describe('getActivityGroupFromEvents', () => {
180188
]);
181189

182190
// Timed out
183-
const timeoutEvents: ActivityHistoryEvent[] = [
191+
const timeoutEvents: ExtendedActivityHistoryEvent[] = [
184192
scheduleActivityTaskEvent,
185193
startActivityTaskEvent,
186194
timeoutActivityTaskEvent,
@@ -194,7 +202,7 @@ describe('getActivityGroupFromEvents', () => {
194202
});
195203

196204
it('should return group eventsMetadata with correct timeLabel', () => {
197-
const events: ActivityHistoryEvent[] = [
205+
const events: ExtendedActivityHistoryEvent[] = [
198206
scheduleActivityTaskEvent,
199207
startActivityTaskEvent,
200208
completeActivityTaskEvent,
@@ -206,4 +214,22 @@ describe('getActivityGroupFromEvents', () => {
206214
'Completed at 07 Sep, 22:16:10 UTC',
207215
]);
208216
});
217+
218+
it('should use correct time label prefix for pending activity events', () => {
219+
const groupWithScheduledState = getActivityGroupFromEvents([
220+
scheduleActivityTaskEvent,
221+
pendingActivityTaskStartEvent,
222+
]);
223+
expect(groupWithScheduledState.eventsMetadata[1].timeLabel).toMatch(
224+
/^Scheduled at/
225+
);
226+
227+
const groupWithStartedState = getActivityGroupFromEvents([
228+
scheduleActivityTaskEvent,
229+
pendingActivityTaskStartEventWithStartedState,
230+
]);
231+
expect(groupWithStartedState.eventsMetadata[1].timeLabel).toMatch(
232+
/^Last started at/
233+
);
234+
});
209235
});

src/views/workflow-history/helpers/get-history-group-from-events/get-activity-group-from-events.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type {
33
ExtendedActivityHistoryEvent,
44
HistoryGroupEventToStatusMap,
55
HistoryGroupEventToStringMap,
6+
PendingActivityTaskStartEvent,
67
} from '../../workflow-history.types';
78
import getCommonHistoryGroupFields from '../get-common-history-group-fields';
89

@@ -26,7 +27,7 @@ export default function getActivityGroupFromEvents(
2627
let scheduleEvent: ExtendedActivityHistoryEvent | undefined;
2728
let timeoutEvent: ExtendedActivityHistoryEvent | undefined;
2829
let startEvent: ExtendedActivityHistoryEvent | undefined;
29-
let pendingStartEvent: ExtendedActivityHistoryEvent | undefined;
30+
let pendingStartEvent: PendingActivityTaskStartEvent | undefined;
3031
let closeEvent: ExtendedActivityHistoryEvent | undefined;
3132

3233
events.forEach((e) => {
@@ -89,6 +90,11 @@ export default function getActivityGroupFromEvents(
8990
activityTaskTimedOutEventAttributes: 'FAILED',
9091
};
9192

93+
const pendingStartEventTimePrefix = pendingStartEvent?.[pendingStartAttr]
94+
.lastStartedTime
95+
? 'Last started at'
96+
: 'Scheduled at';
97+
9298
return {
9399
label,
94100
hasMissingEvents,
@@ -98,7 +104,7 @@ export default function getActivityGroupFromEvents(
98104
events,
99105
eventToStatus,
100106
eventToLabel,
101-
{ pendingActivityTaskStartEventAttributes: 'Last started at' }
107+
{ pendingActivityTaskStartEventAttributes: pendingStartEventTimePrefix }
102108
),
103109
};
104110
}

src/views/workflow-history/helpers/group-history-events.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ export function groupHistoryEvents(
115115
);
116116
} else {
117117
const currentGroup = groupByFirstEventId[groupId];
118-
// add pendingStart to group only if it is schedueled
118+
// add pendingStart to group only if it is scheduled
119119
if (
120120
pa.eventTime &&
121121
currentGroup &&

src/views/workflow-history/helpers/pending-activities-info-to-events.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export default function pendingActivitiesInfoToEvents(
99
switch (activityInfo.state) {
1010
case 'PENDING_ACTIVITY_STATE_SCHEDULED':
1111
case 'PENDING_ACTIVITY_STATE_STARTED':
12+
case 'PENDING_ACTIVITY_STATE_CANCEL_REQUESTED':
1213
return {
1314
attributes: 'pendingActivityTaskStartEventAttributes',
1415
eventTime: activityInfo.lastStartedTime ?? activityInfo.scheduledTime,

src/views/workflow-history/workflow-history.types.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,10 @@ export type PendingDecisionScheduleInfo = Omit<PendingDecisionInfo, 'state'> & {
5858
};
5959

6060
export type PendingActivityStartInfo = Omit<PendingActivityInfo, 'state'> & {
61-
state: 'PENDING_ACTIVITY_STATE_SCHEDULED' | 'PENDING_ACTIVITY_STATE_STARTED';
61+
state:
62+
| 'PENDING_ACTIVITY_STATE_SCHEDULED'
63+
| 'PENDING_ACTIVITY_STATE_STARTED'
64+
| 'PENDING_ACTIVITY_STATE_CANCEL_REQUESTED';
6265
};
6366

6467
export type PendingActivityTaskStartEvent = {

0 commit comments

Comments
 (0)