Skip to content

Commit aa5bba2

Browse files
authored
fix(client): Simplify WorkflowClient interceptors (#956)
1 parent 64761ea commit aa5bba2

File tree

6 files changed

+140
-82
lines changed

6 files changed

+140
-82
lines changed

packages/client/src/interceptors.ts

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,23 @@ import { CompiledWorkflowOptions } from './workflow-options';
1717

1818
export { Next, Headers };
1919

20-
/** Input for WorkflowClientCallsInterceptor.start */
20+
/** Input for WorkflowClientInterceptor.start */
2121
export interface WorkflowStartInput {
2222
/** Name of Workflow to start */
2323
readonly workflowType: string;
2424
readonly headers: Headers;
2525
readonly options: CompiledWorkflowOptions;
2626
}
2727

28-
/** Input for WorkflowClientCallsInterceptor.signal */
28+
/** Input for WorkflowClientInterceptor.signal */
2929
export interface WorkflowSignalInput {
3030
readonly signalName: string;
3131
readonly args: unknown[];
3232
readonly workflowExecution: WorkflowExecution;
3333
readonly headers: Headers;
3434
}
3535

36-
/** Input for WorkflowClientCallsInterceptor.signalWithStart */
36+
/** Input for WorkflowClientInterceptor.signalWithStart */
3737
export interface WorkflowSignalWithStartInput {
3838
readonly workflowType: string;
3939
readonly signalName: string;
@@ -42,7 +42,7 @@ export interface WorkflowSignalWithStartInput {
4242
readonly options: CompiledWorkflowOptions;
4343
}
4444

45-
/** Input for WorkflowClientCallsInterceptor.query */
45+
/** Input for WorkflowClientInterceptor.query */
4646
export interface WorkflowQueryInput {
4747
readonly queryType: string;
4848
readonly args: unknown[];
@@ -51,29 +51,29 @@ export interface WorkflowQueryInput {
5151
readonly headers: Headers;
5252
}
5353

54-
/** Input for WorkflowClientCallsInterceptor.terminate */
54+
/** Input for WorkflowClientInterceptor.terminate */
5555
export interface WorkflowTerminateInput {
5656
readonly workflowExecution: WorkflowExecution;
5757
readonly reason?: string;
5858
readonly details?: unknown[];
5959
readonly firstExecutionRunId?: string;
6060
}
6161

62-
/** Input for WorkflowClientCallsInterceptor.cancel */
62+
/** Input for WorkflowClientInterceptor.cancel */
6363
export interface WorkflowCancelInput {
6464
readonly workflowExecution: WorkflowExecution;
6565
readonly firstExecutionRunId?: string;
6666
}
6767

68-
/** Input for WorkflowClientCallsInterceptor.describe */
68+
/** Input for WorkflowClientInterceptor.describe */
6969
export interface WorkflowDescribeInput {
7070
readonly workflowExecution: WorkflowExecution;
7171
}
7272

7373
/**
7474
* Implement any of these methods to intercept WorkflowClient outbound calls
7575
*/
76-
export interface WorkflowClientCallsInterceptor {
76+
export interface WorkflowClientInterceptor {
7777
/**
7878
* Intercept a service call to startWorkflowExecution
7979
*
@@ -113,22 +113,31 @@ export interface WorkflowClientCallsInterceptor {
113113
describe?: (input: WorkflowDescribeInput, next: Next<this, 'describe'>) => Promise<DescribeWorkflowExecutionResponse>;
114114
}
115115

116+
/** @deprecated: Use WorkflowClientInterceptor instead */
117+
export type WorkflowClientCallsInterceptor = WorkflowClientInterceptor;
118+
119+
/** @deprecated */
116120
export interface WorkflowClientCallsInterceptorFactoryInput {
117121
workflowId: string;
118122
runId?: string;
119123
}
120124

121125
/**
122126
* A function that takes {@link CompiledWorkflowOptions} and returns an interceptor
127+
*
128+
* @deprecated: Please define interceptors directly, without factory
123129
*/
124130
export interface WorkflowClientCallsInterceptorFactory {
125131
(input: WorkflowClientCallsInterceptorFactoryInput): WorkflowClientCallsInterceptor;
126132
}
127133

128134
/**
129135
* A mapping of interceptor type of a list of factory functions
136+
*
137+
* @deprecated: Please define interceptors directly, without factory
130138
*/
131139
export interface WorkflowClientInterceptors {
140+
/** @deprecated */
132141
calls?: WorkflowClientCallsInterceptorFactory[];
133142
}
134143

@@ -164,7 +173,7 @@ export type CreateScheduleOutput = {
164173
* NOTE: Currently only for {@link WorkflowClient} and {@link ScheduleClient}. More will be added later as needed.
165174
*/
166175
export interface ClientInterceptors {
167-
workflow?: WorkflowClientInterceptors;
176+
workflow?: WorkflowClientInterceptors | WorkflowClientInterceptor[];
168177

169178
/**
170179
* @experimental

packages/client/src/workflow-client.ts

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ import { Connection } from './connection';
3838
import { isServerErrorResponse, ServiceError, WorkflowContinuedAsNewError, WorkflowFailedError } from './errors';
3939
import {
4040
WorkflowCancelInput,
41-
WorkflowClientCallsInterceptor,
41+
WorkflowClientInterceptor,
4242
WorkflowClientInterceptors,
4343
WorkflowDescribeInput,
4444
WorkflowQueryInput,
@@ -175,7 +175,8 @@ export interface WorkflowClientOptions {
175175
*
176176
* Useful for injecting auth headers and tracing Workflow executions
177177
*/
178-
interceptors?: WorkflowClientInterceptors;
178+
// eslint-disable-next-line deprecation/deprecation
179+
interceptors?: WorkflowClientInterceptors | WorkflowClientInterceptor[];
179180

180181
/**
181182
* Identity to report to the server
@@ -223,7 +224,7 @@ export function defaultWorkflowClientOptions(): WorkflowClientOptionsWithDefault
223224
dataConverter: {},
224225
// The equivalent in Java is ManagementFactory.getRuntimeMXBean().getName()
225226
identity: `${process.pid}@${os.hostname()}`,
226-
interceptors: {},
227+
interceptors: [],
227228
namespace: 'default',
228229
queryRejectCondition: temporal.api.enums.v1.QueryRejectCondition.QUERY_REJECT_CONDITION_UNSPECIFIED,
229230
};
@@ -274,7 +275,7 @@ export interface GetWorkflowHandleOptions extends WorkflowResultOptions {
274275
interface WorkflowHandleOptions extends GetWorkflowHandleOptions {
275276
workflowId: string;
276277
runId?: string;
277-
interceptors: WorkflowClientCallsInterceptor[];
278+
interceptors: WorkflowClientInterceptor[];
278279
/**
279280
* A runId to use for getting the workflow's result.
280281
*
@@ -362,7 +363,7 @@ export class WorkflowClient {
362363
protected async _start<T extends Workflow>(
363364
workflowTypeOrFunc: string | T,
364365
options: WithWorkflowArgs<T, WorkflowOptions>,
365-
interceptors: WorkflowClientCallsInterceptor[]
366+
interceptors: WorkflowClientInterceptor[]
366367
): Promise<string> {
367368
const workflowType = typeof workflowTypeOrFunc === 'string' ? workflowTypeOrFunc : workflowTypeOrFunc.name;
368369
assertRequiredWorkflowOptions(options);
@@ -386,7 +387,7 @@ export class WorkflowClient {
386387
protected async _signalWithStart<T extends Workflow, SA extends any[]>(
387388
workflowTypeOrFunc: string | T,
388389
options: WithWorkflowArgs<T, WorkflowSignalWithStartOptions<SA>>,
389-
interceptors: WorkflowClientCallsInterceptor[]
390+
interceptors: WorkflowClientInterceptor[]
390391
): Promise<string> {
391392
const workflowType = typeof workflowTypeOrFunc === 'string' ? workflowTypeOrFunc : workflowTypeOrFunc.name;
392393
const { signal, signalArgs, ...rest } = options;
@@ -418,8 +419,7 @@ export class WorkflowClient {
418419
options: WorkflowStartOptions<T>
419420
): Promise<WorkflowHandleWithFirstExecutionRunId<T>> {
420421
const { workflowId } = options;
421-
// Cast is needed because it's impossible to deduce the type in this situation
422-
const interceptors = (this.options.interceptors.calls ?? []).map((ctor) => ctor({ workflowId }));
422+
const interceptors = this.getOrMakeInterceptors(workflowId);
423423
const runId = await this._start(workflowTypeOrFunc, { ...options, workflowId }, interceptors);
424424
// runId is not used in handles created with `start*` calls because these
425425
// handles should allow interacting with the workflow if it continues as new.
@@ -446,7 +446,7 @@ export class WorkflowClient {
446446
options: WithWorkflowArgs<WorkflowFn, WorkflowSignalWithStartOptions<SignalArgs>>
447447
): Promise<WorkflowHandleWithSignaledRunId<WorkflowFn>> {
448448
const { workflowId } = options;
449-
const interceptors = (this.options.interceptors.calls ?? []).map((ctor) => ctor({ workflowId }));
449+
const interceptors = this.getOrMakeInterceptors(workflowId);
450450
const runId = await this._signalWithStart(workflowTypeOrFunc, options, interceptors);
451451
// runId is not used in handles created with `start*` calls because these
452452
// handles should allow interacting with the workflow if it continues as new.
@@ -472,7 +472,7 @@ export class WorkflowClient {
472472
options: WorkflowStartOptions<T>
473473
): Promise<WorkflowResultType<T>> {
474474
const { workflowId } = options;
475-
const interceptors = (this.options.interceptors.calls ?? []).map((ctor) => ctor({ workflowId }));
475+
const interceptors = this.getOrMakeInterceptors(workflowId);
476476
await this._start(workflowTypeOrFunc, options, interceptors);
477477
return await this.result(workflowId, undefined, {
478478
...options,
@@ -912,7 +912,7 @@ export class WorkflowClient {
912912
runId?: string,
913913
options?: GetWorkflowHandleOptions
914914
): WorkflowHandle<T> {
915-
const interceptors = (this.options.interceptors.calls ?? []).map((ctor) => ctor({ workflowId, runId }));
915+
const interceptors = this.getOrMakeInterceptors(workflowId, runId);
916916

917917
return this._createWorkflowHandle({
918918
workflowId,
@@ -951,6 +951,15 @@ export class WorkflowClient {
951951
if (nextPageToken == null || nextPageToken.length == 0) break;
952952
}
953953
}
954+
955+
protected getOrMakeInterceptors(workflowId: string, runId?: string): WorkflowClientInterceptor[] {
956+
if (typeof this.options.interceptors === 'object' && 'calls' in this.options.interceptors) {
957+
// eslint-disable-next-line deprecation/deprecation
958+
const factories = (this.options.interceptors as WorkflowClientInterceptors).calls ?? [];
959+
return factories.map((ctor) => ctor({ workflowId, runId }));
960+
}
961+
return Array.isArray(this.options.interceptors) ? (this.options.interceptors as WorkflowClientInterceptor[]) : [];
962+
}
954963
}
955964

956965
export class QueryRejectedError extends Error {

packages/interceptors-opentelemetry/src/client/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as otel from '@opentelemetry/api';
2-
import { Next, WorkflowClientCallsInterceptor, WorkflowStartInput } from '@temporalio/client';
2+
import { Next, WorkflowClientInterceptor, WorkflowStartInput } from '@temporalio/client';
33
import { headersWithContext, RUN_ID_ATTR_KEY } from '@temporalio/common/lib/otel';
44
import { instrument } from '../instrumentation';
55
import { SpanName, SPAN_DELIMITER } from '../workflow';
@@ -13,14 +13,14 @@ export interface InterceptorOptions {
1313
*
1414
* Wraps the operation in an opentelemetry Span and passes it to the Workflow via headers.
1515
*/
16-
export class OpenTelemetryWorkflowClientCallsInterceptor implements WorkflowClientCallsInterceptor {
16+
export class OpenTelemetryWorkflowClientInterceptor implements WorkflowClientInterceptor {
1717
protected readonly tracer: otel.Tracer;
1818

1919
constructor(options?: InterceptorOptions) {
2020
this.tracer = options?.tracer ?? otel.trace.getTracer('@temporalio/interceptor-client');
2121
}
2222

23-
async start(input: WorkflowStartInput, next: Next<WorkflowClientCallsInterceptor, 'start'>): Promise<string> {
23+
async start(input: WorkflowStartInput, next: Next<WorkflowClientInterceptor, 'start'>): Promise<string> {
2424
return await instrument({
2525
tracer: this.tracer,
2626
spanName: `${SpanName.WORKFLOW_START}${SPAN_DELIMITER}${input.workflowType}`,

packages/interceptors-opentelemetry/src/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,8 @@
1010

1111
export * from './workflow';
1212
export * from './worker';
13-
export { OpenTelemetryWorkflowClientCallsInterceptor } from './client';
13+
export {
14+
OpenTelemetryWorkflowClientInterceptor,
15+
/** deprecated: Use OpenTelemetryWorkflowClientInterceptor instead */
16+
OpenTelemetryWorkflowClientInterceptor as OpenTelemetryWorkflowClientCallsInterceptor,
17+
} from './client';

0 commit comments

Comments
 (0)