Skip to content

Commit 485d061

Browse files
authored
Add pending activities with scheduled state (#851)
* add state scheduled to pending activity * fix eventTime * avoid duplicating lastFailure * update snapshot
1 parent a01c3d7 commit 485d061

File tree

8 files changed

+90
-21
lines changed

8 files changed

+90
-21
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+
pendingActivityTaskStartEventWithScheduledState,
67
pendingDecisionTaskScheduleEvent,
78
} from '@/views/workflow-history/__fixtures__/workflow-history-pending-events';
89

@@ -12,6 +13,7 @@ jest.mock('@/utils/logger');
1213

1314
const pendingEvents = [
1415
pendingActivityTaskStartEvent,
16+
pendingActivityTaskStartEventWithScheduledState,
1517
pendingDecisionTaskScheduleEvent,
1618
];
1719
describe('formatWorkflowHistoryEvent', () => {

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

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,35 @@ exports[`formatWorkflowHistoryEvent should format workflow pendingActivityTaskSt
1616
"gadence-canary-xdc",
1717
"workflow.sanity",
1818
],
19-
"lastFailure": {
20-
"details": "",
21-
"reason": "",
19+
"lastFailureDetails": null,
20+
"lastFailureReason": "",
21+
"lastHeartbeatTime": null,
22+
"lastStartedTime": null,
23+
"lastWorkerIdentity": "",
24+
"maximumAttempts": 10,
25+
"scheduleId": 7,
26+
"scheduledTime": 1970-01-01T00:03:00.000Z,
27+
"startedWorkerIdentity": "",
28+
"state": "started",
29+
}
30+
`;
31+
32+
exports[`formatWorkflowHistoryEvent should format workflow pendingActivityTaskStartEventAttributes to match snapshot 2`] = `
33+
{
34+
"activityId": "0",
35+
"activityType": {
36+
"name": "activity.cron.Start",
2237
},
38+
"attempt": 1,
39+
"eventId": null,
40+
"eventTime": 2024-09-07T22:16:10.599Z,
41+
"eventType": "PendingActivityTaskStart",
42+
"expirationTime": 1970-01-01T00:06:00.000Z,
43+
"heartbeatDetails": [
44+
"1725747370575409843",
45+
"gadence-canary-xdc",
46+
"workflow.sanity",
47+
],
2348
"lastFailureDetails": null,
2449
"lastFailureReason": "",
2550
"lastHeartbeatTime": null,
@@ -29,6 +54,7 @@ exports[`formatWorkflowHistoryEvent should format workflow pendingActivityTaskSt
2954
"scheduleId": 7,
3055
"scheduledTime": 1970-01-01T00:03:00.000Z,
3156
"startedWorkerIdentity": "",
57+
"state": "scheduled",
3258
}
3359
`;
3460

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,38 @@
1-
import omit from 'lodash/omit';
2-
31
import { type PendingActivityTaskStartEvent } from '@/views/workflow-history/workflow-history.types';
42

3+
import formatEnum from '../format-enum';
54
import formatFailureDetails from '../format-failure-details';
65
import formatPayload from '../format-payload';
76
import formatTimestampToDatetime from '../format-timestamp-to-datetime';
87

98
export default function formatPendingActivityTaskStartEvent({
10-
pendingActivityTaskStartEventAttributes: pendingInfo,
9+
pendingActivityTaskStartEventAttributes: {
10+
scheduleId,
11+
state,
12+
lastHeartbeatTime,
13+
lastStartedTime,
14+
scheduledTime,
15+
expirationTime,
16+
heartbeatDetails,
17+
lastFailure,
18+
...eventAttributes
19+
},
1120
eventTime,
1221
eventId,
1322
}: PendingActivityTaskStartEvent) {
1423
return {
15-
...omit(pendingInfo, 'state'),
24+
...eventAttributes,
1625
eventId,
1726
eventTime: formatTimestampToDatetime(eventTime),
1827
eventType: 'PendingActivityTaskStart',
19-
20-
scheduleId: parseInt(pendingInfo.scheduleId),
21-
lastHeartbeatTime: formatTimestampToDatetime(pendingInfo.lastHeartbeatTime),
22-
lastStartedTime: formatTimestampToDatetime(pendingInfo.lastStartedTime),
23-
scheduledTime: formatTimestampToDatetime(pendingInfo.scheduledTime),
24-
expirationTime: formatTimestampToDatetime(pendingInfo.expirationTime),
25-
heartbeatDetails: formatPayload(pendingInfo.heartbeatDetails),
26-
lastFailureDetails: formatFailureDetails(pendingInfo.lastFailure),
27-
lastFailureReason: pendingInfo.lastFailure?.reason,
28+
state: formatEnum(state, 'PENDING_ACTIVITY_STATE', 'pascal'),
29+
scheduleId: parseInt(scheduleId),
30+
lastHeartbeatTime: formatTimestampToDatetime(lastHeartbeatTime),
31+
lastStartedTime: formatTimestampToDatetime(lastStartedTime),
32+
scheduledTime: formatTimestampToDatetime(scheduledTime),
33+
expirationTime: formatTimestampToDatetime(expirationTime),
34+
heartbeatDetails: formatPayload(heartbeatDetails),
35+
lastFailureDetails: formatFailureDetails(lastFailure),
36+
lastFailureReason: lastFailure?.reason,
2837
};
2938
}

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ export const pendingActivityTaskStartSchema = z.object({
2929
pendingActivityTaskStartEventAttributes: z.object({
3030
activityId: z.string(),
3131
activityType: activityTypeSchema.nullable(),
32-
state: z.literal(PendingActivityState.PENDING_ACTIVITY_STATE_STARTED),
32+
state: z.enum([
33+
PendingActivityState.PENDING_ACTIVITY_STATE_SCHEDULED,
34+
PendingActivityState.PENDING_ACTIVITY_STATE_STARTED,
35+
]),
3336
heartbeatDetails: payloadSchema.nullable(),
3437
lastHeartbeatTime: timestampSchema.nullable(),
3538
lastStartedTime: timestampSchema.nullable(),

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import type {
55

66
export const pendingActivityTaskStartEvent = {
77
eventId: null,
8-
computedEventId: 'pending-16',
8+
computedEventId: 'pending-7',
99
attributes: 'pendingActivityTaskStartEventAttributes',
1010
eventTime: {
1111
seconds: '1725747370',
@@ -43,6 +43,14 @@ export const pendingActivityTaskStartEvent = {
4343
},
4444
} as const satisfies PendingActivityTaskStartEvent;
4545

46+
export const pendingActivityTaskStartEventWithScheduledState = {
47+
...pendingActivityTaskStartEvent,
48+
pendingActivityTaskStartEventAttributes: {
49+
...pendingActivityTaskStartEvent.pendingActivityTaskStartEventAttributes,
50+
state: 'PENDING_ACTIVITY_STATE_SCHEDULED',
51+
},
52+
} as const satisfies PendingActivityTaskStartEvent;
53+
4654
export const pendingDecisionTaskScheduleEvent = {
4755
eventId: '2',
4856
attributes: 'pendingDecisionTaskScheduleEventAttributes',

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
import { startDecisionTaskEvent } from '../../__fixtures__/workflow-history-decision-events';
1010
import {
1111
pendingActivityTaskStartEvent,
12+
pendingActivityTaskStartEventWithScheduledState,
1213
pendingDecisionTaskScheduleEvent,
1314
} from '../../__fixtures__/workflow-history-pending-events';
1415
import type { ActivityHistoryEvent } from '../../workflow-history.types';
@@ -151,6 +152,25 @@ describe('groupHistoryEvents', () => {
151152
]);
152153
});
153154

155+
it('should append pending activity start with scheduled state to group that has scheduled activity event only', () => {
156+
const events: ActivityHistoryEvent[] = [scheduleActivityTaskEvent];
157+
const pendingStartActivities = [
158+
pendingActivityTaskStartEventWithScheduledState,
159+
];
160+
(getHistoryEventGroupId as jest.Mock).mockReturnValue('group1');
161+
162+
const result = groupHistoryEvents(events, {
163+
allEvents: events,
164+
pendingScheduleDecision: null,
165+
pendingStartActivities,
166+
});
167+
168+
expect(result.group1.events).toEqual([
169+
...events,
170+
...pendingStartActivities,
171+
]);
172+
});
173+
154174
it('should not append pending activity start to group if it does not have scheduled activity event', () => {
155175
const events: ActivityHistoryEvent[] = [startActivityTaskEvent];
156176
const pendingStartActivities = [pendingActivityTaskStartEvent];

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,16 @@ export default function pendingActivitiesInfoToEvents(
77
): PendingActivityTaskStartEvent[] {
88
const events = activities.map((activityInfo) => {
99
switch (activityInfo.state) {
10+
case 'PENDING_ACTIVITY_STATE_SCHEDULED':
1011
case 'PENDING_ACTIVITY_STATE_STARTED':
1112
return {
1213
attributes: 'pendingActivityTaskStartEventAttributes',
13-
eventTime: activityInfo.lastStartedTime,
14+
eventTime: activityInfo.lastStartedTime ?? activityInfo.scheduledTime,
1415
eventId: null,
1516
computedEventId: `Pending-${activityInfo.scheduleId}`,
1617
pendingActivityTaskStartEventAttributes: {
1718
...activityInfo,
18-
state: 'PENDING_ACTIVITY_STATE_STARTED', // make it clear to ts that the state is started (same as a typeguard)
19+
state: activityInfo.state, // make it clear to ts that the state is start or scheduled (same as a typeguard)
1920
},
2021
} satisfies PendingActivityTaskStartEvent;
2122
default:

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

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

6060
export type PendingActivityStartInfo = Omit<PendingActivityInfo, 'state'> & {
61-
state: 'PENDING_ACTIVITY_STATE_STARTED';
61+
state: 'PENDING_ACTIVITY_STATE_SCHEDULED' | 'PENDING_ACTIVITY_STATE_STARTED';
6262
};
6363

6464
export type PendingActivityTaskStartEvent = {

0 commit comments

Comments
 (0)