Skip to content

Commit 02681a6

Browse files
evangraykfacebook-github-bot
authored andcommitted
Add timeout to gh merge queue query
Summary: When checking for the merge queue support, we've seen cases of the command hanging. Let's just add a timeout to kill the spawned proccess. This makes sure we keep this reasonable. I went with 10 seconds. It's a very simple query, so if it takes more than 1-2 seconds something is wrong. Worst case scenario: the timeout hits when it shouldn't and the repo is detected as not supporting merge queue, which is a minor feature. It would still work otherwise. Reviewed By: muirdm Differential Revision: D76067308 fbshipit-source-id: ab14eecc86629f72273f58095661a0ece57c4c3e
1 parent 5232133 commit 02681a6

2 files changed

Lines changed: 25 additions & 3 deletions

File tree

addons/isl-server/src/github/githubCodeReviewProvider.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ export class GitHubCodeReviewProvider implements CodeReviewProvider {
9090
const data = await this.query<MergeQueueSupportQueryData, MergeQueueSupportQueryVariables>(
9191
MergeQueueSupportQuery,
9292
{},
93+
10_000,
9394
).catch(err => {
9495
this.logger.info('failed to detect merge queue support', err);
9596
return undefined;
@@ -232,8 +233,8 @@ export class GitHubCodeReviewProvider implements CodeReviewProvider {
232233
);
233234
}
234235

235-
private query<D, V>(query: string, variables: V): Promise<D | undefined> {
236-
return queryGraphQL<D, V>(query, variables, this.codeReviewSystem.hostname);
236+
private query<D, V>(query: string, variables: V, timeoutMs?: number): Promise<D | undefined> {
237+
return queryGraphQL<D, V>(query, variables, this.codeReviewSystem.hostname, timeoutMs);
237238
}
238239

239240
public dispose() {

addons/isl-server/src/github/queryGraphQL.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export default async function queryGraphQL<TData, TVariables>(
1313
query: string,
1414
variables: TVariables,
1515
hostname: string,
16+
timeoutMs?: number,
1617
): Promise<TData> {
1718
if (Object.prototype.hasOwnProperty.call(variables, 'query')) {
1819
throw Error('cannot have a variable named query');
@@ -38,12 +39,29 @@ export default async function queryGraphQL<TData, TVariables>(
3839
args.push('--hostname', hostname);
3940
args.push('-f', `query=${query}`);
4041

42+
let timedOut = false;
43+
4144
try {
42-
const {stdout} = await ejeca('gh', args, {
45+
const proc = ejeca('gh', args, {
4346
env: {
4447
...((await Internal.additionalGhEnvVars?.()) ?? {}),
4548
},
4649
});
50+
51+
// TODO: move this into ejeca itself
52+
let timeoutId: NodeJS.Timeout | undefined;
53+
if (timeoutMs != null && timeoutMs > 0) {
54+
timeoutId = setTimeout(() => {
55+
proc.kill('SIGTERM', {forceKillAfterTimeout: 5_000});
56+
timedOut = true;
57+
}, timeoutMs);
58+
proc.on('exit', () => {
59+
clearTimeout(timeoutId);
60+
});
61+
}
62+
63+
const {stdout} = await proc;
64+
4765
const json = JSON.parse(stdout);
4866

4967
if (Array.isArray(json.errors)) {
@@ -64,6 +82,9 @@ export default async function queryGraphQL<TData, TVariables>(
6482
throw new Error(`NotAuthenticatedError: ${(error as Error).stack}`);
6583
}
6684
}
85+
if (timedOut) {
86+
throw new Error(`TimedOutError: ${(error as Error).stack}`);
87+
}
6788
throw error;
6889
}
6990
}

0 commit comments

Comments
 (0)