Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ada5736

Browse files
authored
fix(activity): Set Info.isLocal correctly (temporalio#714)
1 parent c79b052 commit ada5736

File tree

4 files changed

+71
-32
lines changed

4 files changed

+71
-32
lines changed

packages/test/src/activities/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ export async function echo(message?: string): Promise<string> {
2222
return message;
2323
}
2424

25+
export async function isLocal(): Promise<boolean> {
26+
return Context.current().info.isLocal;
27+
}
28+
2529
export async function httpGet(url: string): Promise<string> {
2630
return `<html><body>hello from ${url}</body></html>`;
2731
}

packages/test/src/test-local-activities.ts

Lines changed: 57 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ApplicationFailure, defaultPayloadConverter, WorkflowClient, WorkflowFailedError } from '@temporalio/client';
22
import { temporal } from '@temporalio/proto';
3-
import { Worker } from '@temporalio/worker';
3+
import { bundleWorkflowCode, Worker, WorkflowBundleWithSourceMap } from '@temporalio/worker';
44
import { isCancellation } from '@temporalio/workflow';
55
import anyTest, { TestInterface } from 'ava';
66
import { firstValueFrom, Subject } from 'rxjs';
@@ -10,30 +10,40 @@ import { RUN_INTEGRATION_TESTS } from './helpers';
1010
import * as workflows from './workflows/local-activity-testers';
1111

1212
interface Context {
13+
workflowBundle: WorkflowBundleWithSourceMap;
1314
taskQueue: string;
1415
client: WorkflowClient;
16+
getWorker: () => Promise<Worker>;
1517
}
1618

1719
const test = anyTest as TestInterface<Context>;
1820

21+
test.before(async (t) => {
22+
t.context.workflowBundle = await bundleWorkflowCode({
23+
workflowsPath: require.resolve('./workflows/local-activity-testers'),
24+
});
25+
});
26+
1927
test.beforeEach(async (t) => {
2028
const title = t.title.replace('beforeEach hook for ', '');
2129
const taskQueue = `test-local-activities-${title}`;
22-
t.context = { client: new WorkflowClient(), taskQueue };
23-
});
24-
25-
async function defaultWorker(taskQueue: string) {
26-
return await Worker.create({
30+
t.context = {
31+
...t.context,
32+
client: new WorkflowClient(),
2733
taskQueue,
28-
workflowsPath: require.resolve('./workflows/local-activity-testers'),
29-
activities,
30-
});
31-
}
34+
getWorker: () =>
35+
Worker.create({
36+
taskQueue,
37+
workflowBundle: t.context.workflowBundle,
38+
activities,
39+
}),
40+
};
41+
});
3242

3343
if (RUN_INTEGRATION_TESTS) {
3444
test('Simple local activity works end to end', async (t) => {
35-
const { client, taskQueue } = t.context;
36-
const worker = await defaultWorker(taskQueue);
45+
const { client, taskQueue, getWorker } = t.context;
46+
const worker = await getWorker();
3747
await worker.runUntil(async () => {
3848
const res = await client.execute(workflows.runOneLocalActivity, {
3949
workflowId: uuid4(),
@@ -44,9 +54,29 @@ if (RUN_INTEGRATION_TESTS) {
4454
});
4555
});
4656

57+
test('isLocal is set correctly', async (t) => {
58+
const { client, taskQueue, getWorker } = t.context;
59+
const worker = await getWorker();
60+
await worker.runUntil(async () => {
61+
const res1 = await client.execute(workflows.getIsLocal, {
62+
workflowId: uuid4(),
63+
taskQueue,
64+
args: [true],
65+
});
66+
t.is(res1, true);
67+
68+
const res2 = await client.execute(workflows.getIsLocal, {
69+
workflowId: uuid4(),
70+
taskQueue,
71+
args: [false],
72+
});
73+
t.is(res2, false);
74+
});
75+
});
76+
4777
test('Parallel local activities work end to end', async (t) => {
48-
const { client, taskQueue } = t.context;
49-
const worker = await defaultWorker(taskQueue);
78+
const { client, taskQueue, getWorker } = t.context;
79+
const worker = await getWorker();
5080
await worker.runUntil(async () => {
5181
const args = ['hey', 'ho', 'lets', 'go'];
5282
const handle = await client.start(workflows.runParallelLocalActivities, {
@@ -70,8 +100,8 @@ if (RUN_INTEGRATION_TESTS) {
70100
});
71101

72102
test('Local activity error is propagated properly to the Workflow', async (t) => {
73-
const { client, taskQueue } = t.context;
74-
const worker = await defaultWorker(taskQueue);
103+
const { client, taskQueue, getWorker } = t.context;
104+
const worker = await getWorker();
75105
await worker.runUntil(async () => {
76106
const err: WorkflowFailedError = await t.throwsAsync(
77107
client.execute(workflows.throwAnErrorFromLocalActivity, {
@@ -86,8 +116,8 @@ if (RUN_INTEGRATION_TESTS) {
86116
});
87117

88118
test('Local activity cancellation is propagated properly to the Workflow', async (t) => {
89-
const { client, taskQueue } = t.context;
90-
const worker = await defaultWorker(taskQueue);
119+
const { client, taskQueue, getWorker } = t.context;
120+
const worker = await getWorker();
91121
await worker.runUntil(async () => {
92122
const err: WorkflowFailedError = await t.throwsAsync(
93123
client.execute(workflows.cancelALocalActivity, {
@@ -104,8 +134,8 @@ if (RUN_INTEGRATION_TESTS) {
104134
});
105135

106136
test('Failing local activity can be cancelled', async (t) => {
107-
const { client, taskQueue } = t.context;
108-
const worker = await defaultWorker(taskQueue);
137+
const { client, taskQueue, getWorker } = t.context;
138+
const worker = await getWorker();
109139
await worker.runUntil(async () => {
110140
const err: WorkflowFailedError = await t.throwsAsync(
111141
client.execute(workflows.cancelALocalActivity, {
@@ -122,8 +152,8 @@ if (RUN_INTEGRATION_TESTS) {
122152
});
123153

124154
test('Serial local activities (in the same task) work end to end', async (t) => {
125-
const { client, taskQueue } = t.context;
126-
const worker = await defaultWorker(taskQueue);
155+
const { client, taskQueue, getWorker } = t.context;
156+
const worker = await getWorker();
127157
await worker.runUntil(async () => {
128158
const handle = await client.start(workflows.runSerialLocalActivities, {
129159
workflowId: uuid4(),
@@ -145,8 +175,8 @@ if (RUN_INTEGRATION_TESTS) {
145175
});
146176

147177
test('Local activity does not retry if error is in nonRetryableErrorTypes', async (t) => {
148-
const { client, taskQueue } = t.context;
149-
const worker = await defaultWorker(taskQueue);
178+
const { client, taskQueue, getWorker } = t.context;
179+
const worker = await getWorker();
150180
await worker.runUntil(async () => {
151181
const err: WorkflowFailedError = await t.throwsAsync(
152182
client.execute(workflows.throwAnExplicitNonRetryableErrorFromLocalActivity, {
@@ -259,8 +289,7 @@ if (RUN_INTEGRATION_TESTS) {
259289
});
260290
});
261291

262-
// TODO: fix Core shutdown and reenable this test
263-
test.skip('Worker shutdown while running a local activity completes after completion', async (t) => {
292+
test('Worker shutdown while running a local activity completes after completion', async (t) => {
264293
const { client, taskQueue } = t.context;
265294
const subj = new Subject<void>();
266295
const worker = await Worker.create({
@@ -300,8 +329,8 @@ if (RUN_INTEGRATION_TESTS) {
300329
});
301330

302331
test('Local activity fails if not registered on Worker', async (t) => {
303-
const { client, taskQueue } = t.context;
304-
const worker = await defaultWorker(taskQueue);
332+
const { client, taskQueue, getWorker } = t.context;
333+
const worker = await getWorker();
305334
await worker.runUntil(async () => {
306335
const err: WorkflowFailedError = await t.throwsAsync(
307336
client.execute(workflows.runANonExisitingLocalActivity, {

packages/test/src/workflows/local-activity-testers.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,22 @@
66
import * as wf from '@temporalio/workflow';
77
import type * as activities from '../activities';
88

9-
const { echo, throwAnError, waitForCancellation } = wf.proxyLocalActivities<typeof activities>({
9+
const { echo, isLocal, throwAnError, waitForCancellation } = wf.proxyLocalActivities<typeof activities>({
10+
startToCloseTimeout: '1m',
11+
});
12+
13+
const { isLocal: nonLocalIsLocal } = wf.proxyActivities<typeof activities>({
1014
startToCloseTimeout: '1m',
1115
});
1216

1317
export async function runOneLocalActivity(s: string): Promise<string> {
1418
return await echo(s);
1519
}
1620

21+
export async function getIsLocal(fromInsideLocal: boolean): Promise<boolean> {
22+
return await (fromInsideLocal ? isLocal() : nonLocalIsLocal());
23+
}
24+
1725
export async function runParallelLocalActivities(...ss: string[]): Promise<string[]> {
1826
return await Promise.all(ss.map(echo));
1927
}

packages/worker/src/worker.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -725,7 +725,6 @@ export class Worker {
725725
}
726726
const info = await extractActivityInfo(
727727
task,
728-
false,
729728
this.options.loadedDataConverter,
730729
this.options.namespace
731730
);
@@ -1591,7 +1590,6 @@ type NonNullableObject<T> = { [P in keyof T]-?: NonNullable<T[P]> };
15911590
*/
15921591
async function extractActivityInfo(
15931592
task: coresdk.activity_task.IActivityTask,
1594-
isLocal: boolean,
15951593
dataConverter: LoadedDataConverter,
15961594
activityNamespace: string
15971595
): Promise<ActivityInfo> {
@@ -1605,7 +1603,7 @@ async function extractActivityInfo(
16051603
activityId,
16061604
workflowExecution: start.workflowExecution as NonNullableObject<temporal.api.common.v1.WorkflowExecution>,
16071605
attempt: start.attempt,
1608-
isLocal,
1606+
isLocal: start.isLocal,
16091607
activityType: start.activityType,
16101608
workflowType: start.workflowType,
16111609
heartbeatDetails: await decodeFromPayloadsAtIndex(dataConverter, 0, start.heartbeatDetails),

0 commit comments

Comments
 (0)