Skip to content

Commit eff51e0

Browse files
committed
Fix: a failed invocation to another service should throw an error in the user code
1 parent 6c363d1 commit eff51e0

File tree

3 files changed

+106
-2
lines changed

3 files changed

+106
-2
lines changed

src/state_machine.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1206,7 +1206,7 @@ export class DurableExecutionStateMachine<I, O> implements RestateContext {
12061206
}
12071207
} else if (failure !== undefined) {
12081208
if (pendingMessage.reject !== undefined) {
1209-
pendingMessage.reject(failure);
1209+
pendingMessage.reject(new Error(failure.message));
12101210
this.indexToPendingMsgMap.delete(journalIndex);
12111211
} else {
12121212
// leads to onCallFailure call

test/protoutils.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,8 @@ export function invokeMessage(
185185
serviceName: string,
186186
methodName: string,
187187
parameter: Uint8Array,
188-
value?: Uint8Array
188+
value?: Uint8Array,
189+
failure?: Failure
189190
): Message {
190191
if (value != undefined) {
191192
return new Message(
@@ -197,6 +198,16 @@ export function invokeMessage(
197198
value: Buffer.from(value),
198199
})
199200
);
201+
} else if (failure != undefined) {
202+
return new Message(
203+
INVOKE_ENTRY_MESSAGE_TYPE,
204+
InvokeEntryMessage.create({
205+
serviceName: serviceName,
206+
methodName: methodName,
207+
parameter: Buffer.from(parameter),
208+
failure: failure,
209+
})
210+
);
200211
} else {
201212
return new Message(
202213
INVOKE_ENTRY_MESSAGE_TYPE,

test/send_request.test.ts

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
TestResponse,
2323
} from "../src/generated/proto/test";
2424
import { ProtocolMode } from "../src/generated/proto/discovery";
25+
import { Failure } from "../src/generated/proto/protocol";
2526

2627
class ReverseAwaitOrder implements TestGreeter {
2728
// eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -92,6 +93,36 @@ class FailingSideEffectInBackgroundInvokeGreeter implements TestGreeter {
9293
}
9394
}
9495

96+
class FailingForwardGreetingService implements TestGreeter {
97+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
98+
async greet(request: TestRequest): Promise<TestResponse> {
99+
const ctx = restate.useContext(this);
100+
101+
const client = new TestGreeterClientImpl(ctx);
102+
103+
try {
104+
// This will get an failure back as a completion or replay message
105+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
106+
const greeting = await client.greet(
107+
TestRequest.create({ name: "Francesco" })
108+
);
109+
} catch (error) {
110+
if (error instanceof Error) {
111+
// If we call another service and get back a failure.
112+
// The failure should be thrown in the user code.
113+
return TestResponse.create({
114+
greeting: `Hello ${error.message}`,
115+
});
116+
}
117+
throw new Error("Error is not instanceof Error: " + typeof error);
118+
}
119+
120+
return TestResponse.create({
121+
greeting: `Hello, you shouldn't be here...`,
122+
});
123+
}
124+
}
125+
95126
describe("ReverseAwaitOrder: None completed", () => {
96127
it("should call greet", async () => {
97128
const result = await new TestDriver(
@@ -400,6 +431,68 @@ This gives the following error:
400431
// });
401432
// });
402433

434+
describe("FailingForwardGreetingService: call failed - replay", () => {
435+
it("should call greet", async () => {
436+
const result = await new TestDriver(
437+
protoMetadata,
438+
"TestGreeter",
439+
new FailingForwardGreetingService(),
440+
"/test.TestGreeter/Greet",
441+
[
442+
startMessage(2),
443+
inputMessage(greetRequest("Till")),
444+
invokeMessage(
445+
"test.TestGreeter",
446+
"Greet",
447+
greetRequest("Francesco"),
448+
undefined,
449+
Failure.create({
450+
code: 13,
451+
message: "Sorry, something went terribly wrong...",
452+
})
453+
),
454+
]
455+
).run();
456+
457+
expect(result).toStrictEqual([
458+
outputMessage(
459+
greetResponse("Hello Sorry, something went terribly wrong...")
460+
),
461+
]);
462+
});
463+
});
464+
465+
describe("FailingForwardGreetingService: call failed - completion", () => {
466+
it("should call greet", async () => {
467+
const result = await new TestDriver(
468+
protoMetadata,
469+
"TestGreeter",
470+
new FailingForwardGreetingService(),
471+
"/test.TestGreeter/Greet",
472+
[
473+
startMessage(1),
474+
inputMessage(greetRequest("Till")),
475+
completionMessage(
476+
1,
477+
undefined,
478+
undefined,
479+
Failure.create({
480+
code: 13,
481+
message: "Sorry, something went terribly wrong...",
482+
})
483+
),
484+
]
485+
).run();
486+
487+
expect(result).toStrictEqual([
488+
invokeMessage("test.TestGreeter", "Greet", greetRequest("Francesco")),
489+
outputMessage(
490+
greetResponse("Hello Sorry, something went terribly wrong...")
491+
),
492+
]);
493+
});
494+
});
495+
403496
// async calls
404497
describe("BackgroundInvokeGreeter: background call ", () => {
405498
it("should call greet", async () => {

0 commit comments

Comments
 (0)