Skip to content

Commit 1ed2ad7

Browse files
Change types for diagnostics response (#968)
* Fix Zod schemas for diagnoseWorkflow to transform diagnostics result into lowercase * Add a backwards-compatible check in diagnostics result schema to handle changes made in cadence-workflow/cadence#7094 * Modify fixture for diagnostics result to match post-parsing format * Add fixture for diagnostics query result * Fix types in components
1 parent 0df5296 commit 1ed2ad7

File tree

12 files changed

+259
-109
lines changed

12 files changed

+259
-109
lines changed
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import { type z } from 'zod';
2+
3+
import type workflowDiagnosticsResultSchema from '../schemas/workflow-diagnostics-result-schema';
4+
5+
export const mockDiagnosticsQueryResult = {
6+
DiagnosticsResult: {
7+
Timeouts: null,
8+
Failures: {
9+
Issues: [
10+
{
11+
IssueID: 0,
12+
InvariantType: 'Activity Failed',
13+
Reason:
14+
'The failure is because of an error returned from the service code',
15+
Metadata: {
16+
Identity: 'test-worker@test-host@test-domain@test-workflow@12345',
17+
ActivityType: 'main.helloWorldActivity',
18+
ActivityScheduledID: 43,
19+
ActivityStartedID: 156,
20+
},
21+
},
22+
{
23+
IssueID: 1,
24+
InvariantType: 'Activity Failed',
25+
Reason:
26+
'The failure is because of an error returned from the service code',
27+
Metadata: {
28+
Identity: 'test-worker@test-host@test-domain@test-workflow@12345',
29+
ActivityType: 'main.helloWorldActivity',
30+
ActivityScheduledID: 29,
31+
ActivityStartedID: 234,
32+
},
33+
},
34+
{
35+
IssueID: 2,
36+
InvariantType: 'Activity Failed',
37+
Reason:
38+
'The failure is because of an error returned from the service code',
39+
Metadata: {
40+
Identity: 'test-worker@test-host@test-domain@test-workflow@12345',
41+
ActivityType: 'main.helloWorldActivity',
42+
ActivityScheduledID: 82,
43+
ActivityStartedID: 234,
44+
},
45+
},
46+
{
47+
IssueID: 3,
48+
InvariantType: 'Activity Failed',
49+
Reason:
50+
'The failure is because of an error returned from the service code',
51+
Metadata: {
52+
Identity: 'test-worker@test-host@test-domain@test-workflow@12345',
53+
ActivityType: 'main.helloWorldActivity',
54+
ActivityScheduledID: 102,
55+
ActivityStartedID: 411,
56+
},
57+
},
58+
{
59+
IssueID: 4,
60+
InvariantType: 'Workflow Failed',
61+
Reason:
62+
'The failure is because of an error returned from the service code',
63+
Metadata: {
64+
Identity: 'test-worker@test-host@test-domain@test-workflow@12345',
65+
ActivityType: '',
66+
ActivityScheduledID: 0,
67+
ActivityStartedID: 0,
68+
},
69+
},
70+
],
71+
RootCause: [
72+
{
73+
IssueID: 0,
74+
RootCauseType:
75+
'There is an issue in the worker service that is causing a failure. Check identity for service logs',
76+
Metadata: null,
77+
},
78+
{
79+
IssueID: 1,
80+
RootCauseType:
81+
'There is an issue in the worker service that is causing a failure. Check identity for service logs',
82+
Metadata: null,
83+
},
84+
{
85+
IssueID: 2,
86+
RootCauseType:
87+
'There is an issue in the worker service that is causing a failure. Check identity for service logs',
88+
Metadata: null,
89+
},
90+
{
91+
IssueID: 3,
92+
RootCauseType:
93+
'There is an issue in the worker service that is causing a failure. Check identity for service logs',
94+
Metadata: null,
95+
},
96+
{
97+
IssueID: 4,
98+
RootCauseType:
99+
'There is an issue in the worker service that is causing a failure. Check identity for service logs',
100+
Metadata: null,
101+
},
102+
],
103+
Runbooks: [
104+
'https://cadenceworkflow.io/docs/workflow-troubleshooting/activity-failures/',
105+
],
106+
},
107+
Retries: null,
108+
},
109+
DiagnosticsCompleted: true,
110+
} as const satisfies z.input<typeof workflowDiagnosticsResultSchema>;
Lines changed: 40 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,108 +1,107 @@
11
import { type WorkflowDiagnosticsResult } from '../diagnose-workflow.types';
22

33
export const mockWorkflowDiagnosticsResult = {
4-
DiagnosticsResult: {
4+
result: {
55
Timeouts: null,
66
Failures: {
7-
Issues: [
7+
issues: [
88
{
9-
IssueID: 0,
10-
InvariantType: 'Activity Failed',
11-
Reason:
9+
issueId: 0,
10+
invariantType: 'Activity Failed',
11+
reason:
1212
'The failure is because of an error returned from the service code',
13-
Metadata: {
13+
metadata: {
1414
Identity: 'test-worker@test-host@test-domain@test-workflow@12345',
1515
ActivityType: 'main.helloWorldActivity',
1616
ActivityScheduledID: 43,
1717
ActivityStartedID: 156,
1818
},
1919
},
2020
{
21-
IssueID: 1,
22-
InvariantType: 'Activity Failed',
23-
Reason:
21+
issueId: 1,
22+
invariantType: 'Activity Failed',
23+
reason:
2424
'The failure is because of an error returned from the service code',
25-
Metadata: {
25+
metadata: {
2626
Identity: 'test-worker@test-host@test-domain@test-workflow@12345',
2727
ActivityType: 'main.helloWorldActivity',
2828
ActivityScheduledID: 29,
2929
ActivityStartedID: 234,
3030
},
3131
},
3232
{
33-
IssueID: 2,
34-
InvariantType: 'Activity Failed',
35-
Reason:
33+
issueId: 2,
34+
invariantType: 'Activity Failed',
35+
reason:
3636
'The failure is because of an error returned from the service code',
37-
Metadata: {
37+
metadata: {
3838
Identity: 'test-worker@test-host@test-domain@test-workflow@12345',
3939
ActivityType: 'main.helloWorldActivity',
4040
ActivityScheduledID: 82,
4141
ActivityStartedID: 234,
4242
},
4343
},
4444
{
45-
IssueID: 3,
46-
InvariantType: 'Activity Failed',
47-
Reason:
45+
issueId: 3,
46+
invariantType: 'Activity Failed',
47+
reason:
4848
'The failure is because of an error returned from the service code',
49-
Metadata: {
49+
metadata: {
5050
Identity: 'test-worker@test-host@test-domain@test-workflow@12345',
5151
ActivityType: 'main.helloWorldActivity',
5252
ActivityScheduledID: 102,
5353
ActivityStartedID: 411,
5454
},
5555
},
5656
{
57-
IssueID: 4,
58-
InvariantType: 'Workflow Failed',
59-
Reason:
57+
issueId: 4,
58+
invariantType: 'Workflow Failed',
59+
reason:
6060
'The failure is because of an error returned from the service code',
61-
Metadata: {
61+
metadata: {
6262
Identity: 'test-worker@test-host@test-domain@test-workflow@12345',
6363
ActivityType: '',
6464
ActivityScheduledID: 0,
6565
ActivityStartedID: 0,
6666
},
6767
},
6868
],
69-
RootCause: [
69+
rootCauses: [
7070
{
71-
IssueID: 0,
72-
RootCauseType:
71+
issueId: 0,
72+
rootCauseType:
7373
'There is an issue in the worker service that is causing a failure. Check identity for service logs',
74-
Metadata: null,
74+
metadata: null,
7575
},
7676
{
77-
IssueID: 1,
78-
RootCauseType:
77+
issueId: 1,
78+
rootCauseType:
7979
'There is an issue in the worker service that is causing a failure. Check identity for service logs',
80-
Metadata: null,
80+
metadata: null,
8181
},
8282
{
83-
IssueID: 2,
84-
RootCauseType:
83+
issueId: 2,
84+
rootCauseType:
8585
'There is an issue in the worker service that is causing a failure. Check identity for service logs',
86-
Metadata: null,
86+
metadata: null,
8787
},
8888
{
89-
IssueID: 3,
90-
RootCauseType:
89+
issueId: 3,
90+
rootCauseType:
9191
'There is an issue in the worker service that is causing a failure. Check identity for service logs',
92-
Metadata: null,
92+
metadata: null,
9393
},
9494
{
95-
IssueID: 4,
96-
RootCauseType:
95+
issueId: 4,
96+
rootCauseType:
9797
'There is an issue in the worker service that is causing a failure. Check identity for service logs',
98-
Metadata: null,
98+
metadata: null,
9999
},
100100
],
101-
Runbooks: [
101+
runbook:
102102
'https://cadenceworkflow.io/docs/workflow-troubleshooting/activity-failures/',
103-
],
104103
},
105104
Retries: null,
106105
},
107-
DiagnosticsCompleted: true,
106+
completed: true,
108107
} as const satisfies WorkflowDiagnosticsResult;

src/route-handlers/diagnose-workflow/__tests__/diagnose-workflow.node.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { type QueryWorkflowResponse } from '@/__generated__/proto-ts/uber/cadenc
66
import { GRPCError } from '@/utils/grpc/grpc-error';
77
import { mockGrpcClusterMethods } from '@/utils/route-handlers-middleware/middlewares/__mocks__/grpc-cluster-methods';
88

9+
import { mockDiagnosticsQueryResult } from '../__fixtures__/mock-diagnostics-query-result';
910
import { mockWorkflowDiagnosticsResult } from '../__fixtures__/mock-workflow-diagnostics-result';
1011
import { diagnoseWorkflow } from '../diagnose-workflow';
1112
import {
@@ -97,7 +98,7 @@ describe(diagnoseWorkflow.name, () => {
9798
.mockResolvedValueOnce({
9899
queryResult: {
99100
data: Buffer.from(
100-
JSON.stringify(mockWorkflowDiagnosticsResult)
101+
JSON.stringify(mockDiagnosticsQueryResult)
101102
).toString('base64'),
102103
},
103104
} as QueryWorkflowResponse);
@@ -207,8 +208,8 @@ describe(diagnoseWorkflow.name, () => {
207208
expect(responseJson).toEqual({
208209
parsingError: expect.objectContaining({ name: 'ZodError' }),
209210
result: {
210-
DiagnosticsCompleted: true,
211-
DiagnosticsResult: 'invalid-diagnostics',
211+
completed: true,
212+
result: 'invalid-diagnostics',
212213
},
213214
});
214215
});
@@ -289,7 +290,7 @@ function setup(options?: {
289290
} as Context;
290291

291292
const mockQueryResultJson =
292-
options?.queryResultData || mockWorkflowDiagnosticsResult;
293+
options?.queryResultData || mockDiagnosticsQueryResult;
293294

294295
const mockQueryResponse = {
295296
queryResult: {

src/route-handlers/diagnose-workflow/diagnose-workflow.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,10 @@ export async function diagnoseWorkflow(
7777
return NextResponse.json(
7878
(error
7979
? {
80-
result: unparsedResult,
80+
result: {
81+
completed: unparsedResult.DiagnosticsCompleted,
82+
result: unparsedResult.DiagnosticsResult,
83+
},
8184
parsingError: error,
8285
}
8386
: {
Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
import { z } from 'zod';
22

3-
const workflowDiagnosticsIssueSchema = z.object({
4-
IssueID: z.number(),
5-
InvariantType: z.string(),
6-
Reason: z.string(),
7-
Metadata: z.any(),
8-
});
3+
const workflowDiagnosticsIssueSchema = z
4+
.object({
5+
IssueID: z.number(),
6+
InvariantType: z.string(),
7+
Reason: z.string(),
8+
Metadata: z.any(),
9+
})
10+
.transform(({ IssueID, InvariantType, Reason, Metadata }) => ({
11+
issueId: IssueID,
12+
invariantType: InvariantType,
13+
reason: Reason,
14+
metadata: Metadata,
15+
}));
16+
917
export default workflowDiagnosticsIssueSchema;

src/route-handlers/diagnose-workflow/schemas/workflow-diagnostics-result-schema.ts

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,41 @@ import { z } from 'zod';
33
import workflowDiagnosticsIssueSchema from './workflow-diagnostics-issue-schema';
44
import workflowDiagnosticsRootCauseSchema from './workflow-diagnostics-root-cause-schema';
55

6-
const workflowDiagnosticsResultSchema = z.object({
7-
DiagnosticsResult: z.record(
8-
z.string(),
9-
z
10-
.object({
11-
Issues: z.array(workflowDiagnosticsIssueSchema),
12-
RootCause: z.array(workflowDiagnosticsRootCauseSchema).optional(),
13-
Runbooks: z.array(z.string()).optional().or(z.null()),
14-
})
15-
.or(z.null())
16-
),
17-
DiagnosticsCompleted: z.literal(true),
18-
});
6+
const workflowDiagnosticsResultSchema = z
7+
.object({
8+
DiagnosticsResult: z.record(
9+
z.string(),
10+
z
11+
.object({
12+
Issues: z.array(workflowDiagnosticsIssueSchema),
13+
RootCause: z.array(workflowDiagnosticsRootCauseSchema).optional(),
14+
// https://github.com/cadence-workflow/cadence/pull/7094 introduces a change to return a single runbook instead of an array
15+
// To retain backwards compatibility, we will support both fields but only use the first runbook link if an array is passed
16+
Runbook: z.string().optional().nullable(),
17+
Runbooks: z.array(z.string()).optional().nullable(),
18+
})
19+
.transform(({ Issues, RootCause, Runbook, Runbooks }) => {
20+
let runbook: string | undefined;
21+
22+
if (Runbook) {
23+
runbook = Runbook;
24+
} else if (Runbooks && Runbooks.length > 0) {
25+
runbook = Runbooks[0];
26+
}
27+
28+
return {
29+
issues: Issues,
30+
rootCauses: RootCause,
31+
runbook,
32+
};
33+
})
34+
.nullable()
35+
),
36+
DiagnosticsCompleted: z.literal(true),
37+
})
38+
.transform(({ DiagnosticsCompleted, DiagnosticsResult }) => ({
39+
result: DiagnosticsResult,
40+
completed: DiagnosticsCompleted,
41+
}));
1942

2043
export default workflowDiagnosticsResultSchema;

0 commit comments

Comments
 (0)