Skip to content

Commit 00a773c

Browse files
fix: retry compilation if grpc client needs to be reinitialized
See #2547
1 parent a52bce2 commit 00a773c

File tree

2 files changed

+81
-39
lines changed

2 files changed

+81
-39
lines changed

Diff for: arduino-ide-extension/src/node/core-service-impl.ts

+76-39
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import { Instance } from './cli-protocol/cc/arduino/cli/commands/v1/common_pb';
3636
import {
3737
CompileRequest,
3838
CompileResponse,
39+
InstanceNeedsReinitializationError,
3940
} from './cli-protocol/cc/arduino/cli/commands/v1/compile_pb';
4041
import { Port as RpcPort } from './cli-protocol/cc/arduino/cli/commands/v1/port_pb';
4142
import {
@@ -89,48 +90,84 @@ export class CoreServiceImpl extends CoreClientAware implements CoreService {
8990
compileSummaryHandler
9091
);
9192
const toDisposeOnFinally = new DisposableCollection(handler);
93+
9294
return new Promise<void>((resolve, reject) => {
93-
const call = client.compile(request);
94-
if (cancellationToken) {
95-
toDisposeOnFinally.push(
96-
cancellationToken.onCancellationRequested(() => call.cancel())
95+
let hasRetried = false;
96+
97+
const handleUnexpectedError = (error: Error) => {
98+
console.error(
99+
'Unexpected error occurred while compiling the sketch.',
100+
error
97101
);
98-
}
99-
call
100-
.on('data', handler.onData)
101-
.on('error', (error) => {
102-
if (!ServiceError.is(error)) {
103-
console.error(
104-
'Unexpected error occurred while compiling the sketch.',
105-
error
106-
);
107-
reject(error);
108-
return;
109-
}
110-
if (ServiceError.isCancel(error)) {
111-
console.log(userAbort);
112-
reject(UserAbortApplicationError());
113-
return;
114-
}
115-
const compilerErrors = tryParseError({
116-
content: handler.content,
117-
sketch: options.sketch,
118-
});
119-
const message = nls.localize(
120-
'arduino/compile/error',
121-
'Compilation error: {0}',
122-
compilerErrors
123-
.map(({ message }) => message)
124-
.filter(notEmpty)
125-
.shift() ?? error.details
126-
);
127-
this.sendResponse(
128-
error.details + '\n\n' + message,
129-
OutputMessage.Severity.Error
102+
reject(error);
103+
};
104+
105+
const handleCancellationError = () => {
106+
console.log(userAbort);
107+
reject(UserAbortApplicationError());
108+
};
109+
110+
const handleInstanceNeedsReinitializationError = async (
111+
error: ServiceError & InstanceNeedsReinitializationError
112+
) => {
113+
if (!hasRetried) {
114+
hasRetried = true;
115+
await this.refresh();
116+
return startCompileStream();
117+
}
118+
119+
// If error persists, send the error message to the output
120+
parseAndSendErrorResponse(error);
121+
};
122+
123+
const parseAndSendErrorResponse = (error: ServiceError) => {
124+
const compilerErrors = tryParseError({
125+
content: handler.content,
126+
sketch: options.sketch,
127+
});
128+
const message = nls.localize(
129+
'arduino/compile/error',
130+
'Compilation error: {0}',
131+
compilerErrors
132+
.map(({ message }) => message)
133+
.filter(notEmpty)
134+
.shift() ?? error.details
135+
);
136+
this.sendResponse(
137+
error.details + '\n\n' + message,
138+
OutputMessage.Severity.Error
139+
);
140+
reject(CoreError.VerifyFailed(message, compilerErrors));
141+
};
142+
143+
const handleError = async (error: Error) => {
144+
if (!ServiceError.is(error)) return handleUnexpectedError(error);
145+
if (ServiceError.isCancel(error)) return handleCancellationError();
146+
147+
if (
148+
ServiceError.isInstanceOf(error, InstanceNeedsReinitializationError)
149+
) {
150+
return await handleInstanceNeedsReinitializationError(error);
151+
}
152+
153+
parseAndSendErrorResponse(error);
154+
};
155+
156+
const startCompileStream = () => {
157+
const call = client.compile(request);
158+
if (cancellationToken) {
159+
toDisposeOnFinally.push(
160+
cancellationToken.onCancellationRequested(() => call.cancel())
130161
);
131-
reject(CoreError.VerifyFailed(message, compilerErrors));
132-
})
133-
.on('end', resolve);
162+
}
163+
164+
call
165+
.on('data', handler.onData)
166+
.on('error', handleError)
167+
.on('end', resolve);
168+
};
169+
170+
startCompileStream();
134171
}).finally(() => {
135172
toDisposeOnFinally.dispose();
136173
if (!isCompileSummary(compileSummary)) {

Diff for: arduino-ide-extension/src/node/service-error.ts

+5
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,18 @@ import { Status } from './cli-protocol/google/rpc/status_pb';
33
import { stringToUint8Array } from '../common/utils';
44
import { Status as StatusCode } from '@grpc/grpc-js/build/src/constants';
55
import { ProgrammerIsRequiredForUploadError } from './cli-protocol/cc/arduino/cli/commands/v1/upload_pb';
6+
import { InstanceNeedsReinitializationError } from './cli-protocol/cc/arduino/cli/commands/v1/compile_pb';
67

78
type ProtoError = typeof ProgrammerIsRequiredForUploadError;
89
const protoErrorsMap = new Map<string, ProtoError>([
910
[
1011
'cc.arduino.cli.commands.v1.ProgrammerIsRequiredForUploadError',
1112
ProgrammerIsRequiredForUploadError,
1213
],
14+
[
15+
'cc.arduino.cli.commands.v1.InstanceNeedsReinitializationError',
16+
InstanceNeedsReinitializationError,
17+
],
1318
// handle other cli defined errors here
1419
]);
1520

0 commit comments

Comments
 (0)