Skip to content

Commit d19ce60

Browse files
committed
More fixes
1 parent 075da30 commit d19ce60

File tree

2 files changed

+20
-7
lines changed

2 files changed

+20
-7
lines changed

modal-js/src/function.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,17 @@ import type { LookupOptions } from "./app";
1212
import { client } from "./client";
1313
import { FunctionCall } from "./function_call";
1414
import { environmentName } from "./config";
15-
import { NotFoundError } from "./errors";
15+
import { InternalFailure, NotFoundError } from "./errors";
1616
import { dumps } from "./pickle";
1717
import { ClientError, Status } from "nice-grpc";
1818
import { ControlPlaneInvocation } from "./invocation";
1919

2020
// From: modal/_utils/blob_utils.py
2121
const maxObjectSizeBytes = 2 * 1024 * 1024; // 2 MiB
2222

23+
// From: client/modal/_functions.py
24+
const maxSystemRetries = 8;
25+
2326
/** Represents a deployed Modal Function, which can be invoked remotely. */
2427
export class Function_ {
2528
readonly functionId: string;
@@ -62,7 +65,19 @@ export class Function_ {
6265
input,
6366
FunctionCallInvocationType.FUNCTION_CALL_INVOCATION_TYPE_SYNC,
6467
);
65-
return await invocation.await();
68+
let retryCount = 0;
69+
while (true) {
70+
try {
71+
return await invocation.await();
72+
} catch (err) {
73+
if (err instanceof InternalFailure && retryCount <= maxSystemRetries) {
74+
await invocation.retry(retryCount);
75+
retryCount++;
76+
} else {
77+
throw err;
78+
}
79+
}
80+
}
6681
}
6782

6883
// Spawn a single input into a remote function.

modal-js/src/invocation.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export interface Invocation {
3030
*/
3131
await(): Promise<any>;
3232

33-
retry(): Promise<void>;
33+
retry(retryCount: number): Promise<void>;
3434
}
3535

3636
/**
@@ -41,7 +41,6 @@ export class ControlPlaneInvocation implements Invocation {
4141
private readonly input?: FunctionInput;
4242
private readonly functionCallJwt?: string;
4343
private inputJwt?: string;
44-
private retryCount: number = 0;
4544

4645
private constructor(
4746
functionCallId: string,
@@ -81,7 +80,7 @@ export class ControlPlaneInvocation implements Invocation {
8180
return await pollControlPlaneForOutput(this.functionCallId, timeout);
8281
}
8382

84-
async retry(): Promise<void> {
83+
async retry(retryCount: number): Promise<void> {
8584
// we do not expect this to happen
8685
if (!this.input) {
8786
throw new Error("Cannot retry function invocation - input missing");
@@ -90,15 +89,14 @@ export class ControlPlaneInvocation implements Invocation {
9089
const retryItem: FunctionRetryInputsItem = {
9190
inputJwt: this.inputJwt!,
9291
input: this.input,
93-
retryCount: this.retryCount,
92+
retryCount: retryCount,
9493
};
9594

9695
const functionRetryResponse = await client.functionRetryInputs({
9796
functionCallJwt: this.functionCallJwt,
9897
inputs: [retryItem],
9998
});
10099
this.inputJwt = functionRetryResponse.inputJwts[0];
101-
this.retryCount += 1;
102100
}
103101

104102
private static async execFunctionCall(

0 commit comments

Comments
 (0)