Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 4cf9909

Browse files
fix: retry compilation if grpc client needs to be reinitialized (#2548)
* fix: use `Status` enum for status code in `ServiceError` type guards This change resolves the issue where the intersection of `ServiceError` error codes of type `number` resulted in the `never` type due to conflict between number and `State` enum if `StatusObject` * feat: add `isInvalidArgument` type guard to `ServiceError` * fix: retry compilation if grpc client needs to be reinitialized See #2547
1 parent 41844c9 commit 4cf9909

File tree

2 files changed

+91
-40
lines changed

2 files changed

+91
-40
lines changed

‎arduino-ide-extension/src/node/core-service-impl.ts‎

Lines changed: 76 additions & 39 deletions
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+
// If error persists, send the error message to the output
115+
return parseAndSendErrorResponse(error);
116+
}
117+
118+
hasRetried = true;
119+
await this.refresh();
120+
return startCompileStream();
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)) {

‎arduino-ide-extension/src/node/service-error.ts‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,37 @@
11
import { Metadata, StatusObject } from '@grpc/grpc-js';
22
import { Status } from './cli-protocol/google/rpc/status_pb';
33
import { stringToUint8Array } from '../common/utils';
4+
import { Status as StatusCode } from '@grpc/grpc-js/build/src/constants';
45
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';
57

68
type ProtoError = typeof ProgrammerIsRequiredForUploadError;
79
const protoErrorsMap = new Map<string, ProtoError>([
810
[
911
'cc.arduino.cli.commands.v1.ProgrammerIsRequiredForUploadError',
1012
ProgrammerIsRequiredForUploadError,
1113
],
14+
[
15+
'cc.arduino.cli.commands.v1.InstanceNeedsReinitializationError',
16+
InstanceNeedsReinitializationError,
17+
],
1218
// handle other cli defined errors here
1319
]);
1420

1521
export type ServiceError = StatusObject & Error;
1622
export namespace ServiceError {
17-
export function isCancel(arg: unknown): arg is ServiceError & { code: 1 } {
23+
export function isCancel(
24+
arg: unknown
25+
): arg is ServiceError & { code: StatusCode.CANCELLED } {
1826
return is(arg) && arg.code === 1; // https://grpc.github.io/grpc/core/md_doc_statuscodes.html
1927
}
2028

29+
export function isInvalidArgument(
30+
arg: unknown
31+
): arg is ServiceError & { code: StatusCode.INVALID_ARGUMENT } {
32+
return is(arg) && arg.code === 3; // https://grpc.github.io/grpc/core/md_doc_statuscodes.html
33+
}
34+
2135
export function is(arg: unknown): arg is ServiceError {
2236
return arg instanceof Error && isStatusObject(arg);
2337
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /