Skip to content

Commit 6af2e2c

Browse files
committed
schedule metadata test, fix schedule action decode
1 parent 2dab40d commit 6af2e2c

File tree

8 files changed

+133
-82
lines changed

8 files changed

+133
-82
lines changed

packages/client/src/schedule-helpers.ts

+16-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import Long from 'long'; // eslint-disable-line import/no-named-as-default
2-
import { compileRetryPolicy, decompileRetryPolicy, extractWorkflowType, JsonPayloadConverter, LoadedDataConverter } from '@temporalio/common';
2+
import {
3+
compileRetryPolicy,
4+
decompileRetryPolicy,
5+
extractWorkflowType,
6+
JsonPayloadConverter,
7+
LoadedDataConverter,
8+
} from '@temporalio/common';
39
import {
410
encodeUnifiedSearchAttributes,
511
decodeSearchAttributes,
@@ -239,7 +245,7 @@ export async function encodeScheduleAction(
239245
action: CompiledScheduleAction,
240246
headers: Headers
241247
): Promise<temporal.api.schedule.v1.IScheduleAction> {
242-
const jsonConverter = new JsonPayloadConverter()
248+
const jsonConverter = new JsonPayloadConverter();
243249
return {
244250
startWorkflow: {
245251
workflowId: action.workflowId,
@@ -263,10 +269,10 @@ export async function encodeScheduleAction(
263269
}
264270
: undefined,
265271
header: { fields: headers },
266-
userMetadata: {
267-
summary: jsonConverter.toPayload(action.staticSummary),
268-
details: jsonConverter.toPayload(action.staticDetails)
269-
}
272+
userMetadata: {
273+
summary: jsonConverter.toPayload(action.staticSummary),
274+
details: jsonConverter.toPayload(action.staticDetails),
275+
},
270276
},
271277
};
272278
}
@@ -316,6 +322,8 @@ export async function decodeScheduleAction(
316322
pb: temporal.api.schedule.v1.IScheduleAction
317323
): Promise<ScheduleDescriptionAction> {
318324
if (pb.startWorkflow) {
325+
const jsonConverter = new JsonPayloadConverter();
326+
const userMetadata = pb.startWorkflow?.userMetadata;
319327
return {
320328
type: 'startWorkflow',
321329
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
@@ -332,6 +340,8 @@ export async function decodeScheduleAction(
332340
workflowExecutionTimeout: optionalTsToMs(pb.startWorkflow.workflowExecutionTimeout),
333341
workflowRunTimeout: optionalTsToMs(pb.startWorkflow.workflowRunTimeout),
334342
workflowTaskTimeout: optionalTsToMs(pb.startWorkflow.workflowTaskTimeout),
343+
staticSummary: userMetadata?.summary ? jsonConverter.fromPayload(userMetadata.summary) : undefined,
344+
staticDetails: userMetadata?.details ? jsonConverter.fromPayload(userMetadata.details) : undefined,
335345
};
336346
}
337347
throw new TypeError('Unsupported schedule action');

packages/client/src/workflow-client.ts

+7-7
Original file line numberDiff line numberDiff line change
@@ -1229,8 +1229,8 @@ export class WorkflowClient extends BaseClient {
12291229
header: { fields: headers },
12301230
userMetadata: {
12311231
summary: jsonConverter.toPayload(options?.staticSummary),
1232-
details: jsonConverter.toPayload(options?.staticDetails)
1233-
}
1232+
details: jsonConverter.toPayload(options?.staticDetails),
1233+
},
12341234
};
12351235
try {
12361236
return (await this.workflowService.signalWithStartWorkflowExecution(req)).runId;
@@ -1271,7 +1271,7 @@ export class WorkflowClient extends BaseClient {
12711271
protected async createStartWorkflowRequest(input: WorkflowStartInput): Promise<StartWorkflowExecutionRequest> {
12721272
const { options: opts, workflowType, headers } = input;
12731273
const { identity, namespace } = this.options;
1274-
const jsonConverter = new JsonPayloadConverter()
1274+
const jsonConverter = new JsonPayloadConverter();
12751275
return {
12761276
namespace,
12771277
identity,
@@ -1301,8 +1301,8 @@ export class WorkflowClient extends BaseClient {
13011301
header: { fields: headers },
13021302
userMetadata: {
13031303
summary: jsonConverter.toPayload(opts?.staticSummary),
1304-
details: jsonConverter.toPayload(opts?.staticDetails)
1305-
}
1304+
details: jsonConverter.toPayload(opts?.staticDetails),
1305+
},
13061306
};
13071307
}
13081308

@@ -1436,8 +1436,8 @@ export class WorkflowClient extends BaseClient {
14361436
workflowExecution: { workflowId, runId },
14371437
});
14381438
const info = await executionInfoFromRaw(raw.workflowExecutionInfo ?? {}, this.client.dataConverter, raw);
1439-
const jsonConverter = new JsonPayloadConverter()
1440-
const userMetadata = raw.executionConfig?.userMetadata
1439+
const jsonConverter = new JsonPayloadConverter();
1440+
const userMetadata = raw.executionConfig?.userMetadata;
14411441
return {
14421442
...info,
14431443
staticDetails: userMetadata?.details ? jsonConverter.fromPayload(userMetadata.details) : undefined,

packages/common/src/workflow-options.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -192,16 +192,16 @@ export interface BaseWorkflowOptions {
192192
typedSearchAttributes?: SearchAttributePair[] | TypedSearchAttributes;
193193

194194
/**
195-
* General fixed details for this workflow execution that may appear in UI/CLI.
195+
* General fixed details for this workflow execution that may appear in UI/CLI.
196196
* This can be in Temporal markdown format and can span multiple lines.
197-
*
198-
* @experimental
197+
*
198+
* @experimental
199199
*/
200200
staticDetails?: string;
201201
/**
202202
* A single-line fixed summary for this workflow execution that may appear in the UI/CLI.
203203
* This can be in single-line Temporal markdown format.
204-
*
204+
*
205205
* @experimental
206206
*/
207207
staticSummary?: string;

packages/test/src/test-integration-workflows.ts

+31-28
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,19 @@ import { CancelReason } from '@temporalio/worker/lib/activity';
1010
import * as workflow from '@temporalio/workflow';
1111
import { defineQuery, defineSignal, setHandler } from '@temporalio/workflow';
1212
import { SdkFlags } from '@temporalio/workflow/lib/flags';
13-
import { ActivityCancellationType, ApplicationFailure, JsonPayloadConverter, WorkflowExecutionAlreadyStartedError } from '@temporalio/common';
13+
import {
14+
ActivityCancellationType,
15+
ApplicationFailure,
16+
JsonPayloadConverter,
17+
WorkflowExecutionAlreadyStartedError,
18+
} from '@temporalio/common';
19+
import { temporal } from '@temporalio/proto';
1420
import { signalSchedulingWorkflow } from './activities/helpers';
1521
import { activityStartedSignal } from './workflows/definitions';
1622
import * as workflows from './workflows';
1723
import { Context, helpers, makeTestFunction } from './helpers-integration';
1824
import { overrideSdkInternalFlag } from './mock-internal-flags';
1925
import { asSdkLoggerSink, loadHistory, RUN_TIME_SKIPPING_TESTS } from './helpers';
20-
import { temporal } from '@temporalio/proto';
2126

2227
const test = makeTestFunction({
2328
workflowsPath: __filename,
@@ -1307,38 +1312,38 @@ test('Count workflow executions', async (t) => {
13071312

13081313
export async function userMetadataWorkflow(): Promise<string> {
13091314
let done = false;
1310-
const signalDef = defineSignal('done')
1311-
setHandler(signalDef, () => { done = true })
1312-
1315+
const signalDef = defineSignal('done');
1316+
setHandler(signalDef, () => {
1317+
done = true;
1318+
});
1319+
13131320
// That workflow should call an activity (with summary)
1314-
const { activityWithSummary } = workflow
1315-
.proxyActivities({ scheduleToCloseTimeout: '10s' })
1316-
.withSummaries({
1317-
activityWithSummary: 'activity summary'
1318-
})
1319-
await activityWithSummary()
1321+
const { activityWithSummary } = workflow.proxyActivities({ scheduleToCloseTimeout: '10s' }).withSummaries({
1322+
activityWithSummary: 'activity summary',
1323+
});
1324+
await activityWithSummary();
13201325
// Should have a timer (with summary)
1321-
await workflow.sleep(5, "timer summary")
1326+
await workflow.sleep(5, 'timer summary');
13221327
// Set current details
13231328
workflow.setCurrentDetails('current wf details');
13241329
// Unblock on var -> query current details (or return)
13251330
await workflow.condition(() => done);
13261331
return workflow.getCurrentDetails();
13271332
}
13281333

1329-
test('User metadata', async (t) => {
1334+
test('User metadata on workflow, timer, activity', async (t) => {
13301335
const { createWorker, startWorkflow } = helpers(t);
13311336
const worker = await createWorker({
13321337
activities: {
1333-
async activityWithSummary() {}
1334-
}
1338+
async activityWithSummary() {},
1339+
},
13351340
});
13361341

13371342
await worker.runUntil(async () => {
13381343
// Start a workflow with static details
13391344
const handle = await startWorkflow(userMetadataWorkflow, {
1340-
staticSummary: "wf static summary",
1341-
staticDetails: "wf static details"
1345+
staticSummary: 'wf static summary',
1346+
staticDetails: 'wf static details',
13421347
});
13431348
// Describe workflow -> static summary, static details
13441349
const desc = await handle.describe();
@@ -1350,15 +1355,13 @@ test('User metadata', async (t) => {
13501355
t.true(res === 'current wf details');
13511356

13521357
// Get history events for timer and activity summaries.
1353-
const resp = await t.context.env.client.workflowService.getWorkflowExecutionHistory(
1354-
{
1355-
namespace: t.context.env.client.options.namespace,
1356-
execution: {
1357-
workflowId: handle.workflowId,
1358-
runId: handle.firstExecutionRunId
1359-
},
1360-
}
1361-
);
1358+
const resp = await t.context.env.client.workflowService.getWorkflowExecutionHistory({
1359+
namespace: t.context.env.client.options.namespace,
1360+
execution: {
1361+
workflowId: handle.workflowId,
1362+
runId: handle.firstExecutionRunId,
1363+
},
1364+
});
13621365
const jsonConverter = new JsonPayloadConverter();
13631366
for (const event of resp.history?.events ?? []) {
13641367
if (event.eventType === temporal.api.enums.v1.EventType.EVENT_TYPE_WORKFLOW_EXECUTION_STARTED) {
@@ -1372,10 +1375,10 @@ test('User metadata', async (t) => {
13721375
}
13731376

13741377
// Run metadata query -> get current details
1375-
const wfMetadata = await handle.query('__temporal_workflow_metadata') as temporal.api.sdk.v1.IWorkflowMetadata;
1378+
const wfMetadata = (await handle.query('__temporal_workflow_metadata')) as temporal.api.sdk.v1.IWorkflowMetadata;
13761379
t.deepEqual(wfMetadata.definition?.signalDefinitions?.length, 1);
13771380
t.deepEqual(wfMetadata.definition?.signalDefinitions?.[0].name, 'done');
13781381
t.deepEqual(wfMetadata.definition?.queryDefinitions?.length, 3); // default queries
13791382
t.deepEqual(wfMetadata.currentDetails, 'current wf details');
13801383
});
1381-
});
1384+
});

packages/test/src/test-schedules.ts

+27
Original file line numberDiff line numberDiff line change
@@ -758,4 +758,31 @@ if (RUN_INTEGRATION_TESTS) {
758758
await handle.delete();
759759
}
760760
});
761+
762+
test.serial('User metadata on schedule', async (t) => {
763+
const { client } = t.context;
764+
const scheduleId = `schedule-with-user-metadata-${randomUUID()}`;
765+
const handle = await client.schedule.create({
766+
scheduleId,
767+
spec: {},
768+
action: {
769+
type: 'startWorkflow',
770+
workflowType: dummyWorkflow,
771+
taskQueue,
772+
staticSummary: 'schedule static summary',
773+
staticDetails: 'schedule static details',
774+
},
775+
});
776+
777+
try {
778+
const describedSchedule = await handle.describe();
779+
t.deepEqual(describedSchedule.spec.calendars, []);
780+
t.deepEqual(describedSchedule.spec.intervals, []);
781+
t.deepEqual(describedSchedule.spec.skip, []);
782+
t.deepEqual(describedSchedule.action.staticSummary, 'schedule static summary');
783+
t.deepEqual(describedSchedule.action.staticDetails, 'schedule static details');
784+
} finally {
785+
await handle.delete();
786+
}
787+
});
761788
}

packages/workflow/src/interceptors.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*/
88

99
import { ActivityOptions, Headers, LocalActivityOptions, Next, Timestamp, WorkflowExecution } from '@temporalio/common';
10-
import type { coresdk, temporal } from '@temporalio/proto';
10+
import type { coresdk } from '@temporalio/proto';
1111
import { ChildWorkflowOptionsWithDefaults, ContinueAsNewOptions } from './interfaces';
1212

1313
export { Next, Headers };
@@ -105,7 +105,7 @@ export interface StartChildWorkflowExecutionInput {
105105

106106
/**
107107
* User metadata that can be attached to workflow commands.
108-
*
108+
*
109109
* Current used for:
110110
* - startTimer, scheduleActivity/scheduleLocalActivity commands
111111
* - internal metadata query
@@ -122,7 +122,7 @@ export interface UserMetadata {
122122
*/
123123
export interface WorkflowCommandOptions {
124124
/** User metadata for the command that may be persisted to history */
125-
readonly userMetadata?: UserMetadata
125+
readonly userMetadata?: UserMetadata;
126126
}
127127

128128
/** Input for WorkflowOutboundCallsInterceptor.startTimer */

packages/workflow/src/internals.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,7 @@ export class Activator implements ActivationHandler {
417417

418418
public readonly registeredActivityNames: Set<string>;
419419

420-
public currentDetails: string = "";
420+
public currentDetails: string = '';
421421

422422
constructor({
423423
info,

0 commit comments

Comments
 (0)