mirror of
https://github.com/compiler-explorer/compiler-explorer.git
synced 2025-12-27 09:23:52 -05:00
Attempt to detect faulty compiler/language population (#6610)
This commit is contained in:
13
app.ts
13
app.ts
@@ -538,10 +538,16 @@ async function main() {
|
||||
if (opts.prediscovered) {
|
||||
const prediscoveredCompilersJson = await fs.readFile(opts.prediscovered, 'utf8');
|
||||
initialCompilers = JSON.parse(prediscoveredCompilersJson);
|
||||
await compilerFinder.loadPrediscovered(initialCompilers);
|
||||
const prediscResult = await compilerFinder.loadPrediscovered(initialCompilers);
|
||||
if (prediscResult.length === 0) {
|
||||
throw new Error('Unexpected failure, no compilers found!');
|
||||
}
|
||||
} else {
|
||||
const initialFindResults = await compilerFinder.find();
|
||||
initialCompilers = initialFindResults.compilers;
|
||||
if (initialCompilers.length === 0) {
|
||||
throw new Error('Unexpected failure, no compilers found!');
|
||||
}
|
||||
if (defArgs.ensureNoCompilerClash) {
|
||||
logger.warn('Ensuring no compiler ids clash');
|
||||
if (initialFindResults.foundClash) {
|
||||
@@ -642,7 +648,10 @@ async function main() {
|
||||
}),
|
||||
)
|
||||
// Handle healthchecks at the root, as they're not expected from the outside world
|
||||
.use('/healthcheck', new healthCheck.HealthCheckHandler(compilationQueue, healthCheckFilePath).handle)
|
||||
.use(
|
||||
'/healthcheck',
|
||||
new healthCheck.HealthCheckHandler(compilationQueue, healthCheckFilePath, compileHandler).handle,
|
||||
)
|
||||
.use(httpRoot, router)
|
||||
.use((req, res, next) => {
|
||||
next({status: 404, message: `page "${req.path}" could not be found`});
|
||||
|
||||
@@ -62,3 +62,7 @@ export type CompileRequestTextBody = {
|
||||
skipAsm: string;
|
||||
filterAnsi?: string;
|
||||
};
|
||||
|
||||
export interface ICompileHandler {
|
||||
hasLanguages(): boolean;
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ import {
|
||||
FiledataPair,
|
||||
} from '../../types/compilation/compilation.interfaces.js';
|
||||
import {CompilerOverrideOptions} from '../../types/compilation/compiler-overrides.interfaces.js';
|
||||
import {ICompiler, PreliminaryCompilerInfo} from '../../types/compiler.interfaces.js';
|
||||
import {CompilerInfo, ICompiler, PreliminaryCompilerInfo} from '../../types/compiler.interfaces.js';
|
||||
import {ParseFiltersAndOutputOptions} from '../../types/features/filters.interfaces.js';
|
||||
import {ResultLine} from '../../types/resultline/resultline.interfaces.js';
|
||||
import {BaseCompiler} from '../base-compiler.js';
|
||||
@@ -54,7 +54,12 @@ import {SentryCapture} from '../sentry.js';
|
||||
import {KnownBuildMethod} from '../stats.js';
|
||||
import * as utils from '../utils.js';
|
||||
|
||||
import {CompileRequestJsonBody, CompileRequestQueryArgs, CompileRequestTextBody} from './compile.interfaces.js';
|
||||
import {
|
||||
CompileRequestJsonBody,
|
||||
CompileRequestQueryArgs,
|
||||
CompileRequestTextBody,
|
||||
ICompileHandler,
|
||||
} from './compile.interfaces.js';
|
||||
|
||||
temp.track();
|
||||
|
||||
@@ -97,7 +102,7 @@ export type ParsedRequest = {
|
||||
libraries: CompileChildLibraries[];
|
||||
};
|
||||
|
||||
export class CompileHandler {
|
||||
export class CompileHandler implements ICompileHandler {
|
||||
private compilersById: Record<string, Record<string, BaseCompiler>> = {};
|
||||
private readonly compilerEnv: CompilationEnvironment;
|
||||
private readonly textBanner: string;
|
||||
@@ -200,6 +205,14 @@ export class CompileHandler {
|
||||
});
|
||||
}
|
||||
|
||||
hasLanguages(): boolean {
|
||||
try {
|
||||
return Object.keys(this.compilersById).length > 0;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async create(compiler: PreliminaryCompilerInfo): Promise<ICompiler | null> {
|
||||
const isPrediscovered = !!compiler.version;
|
||||
|
||||
@@ -253,7 +266,10 @@ export class CompileHandler {
|
||||
}
|
||||
}
|
||||
|
||||
async setCompilers(compilers: PreliminaryCompilerInfo[], clientOptions: ClientOptionsType) {
|
||||
async setCompilers(
|
||||
compilers: PreliminaryCompilerInfo[],
|
||||
clientOptions: ClientOptionsType,
|
||||
): Promise<CompilerInfo[]> {
|
||||
// Be careful not to update this.compilersById until we can replace it entirely.
|
||||
const compilersById = {};
|
||||
try {
|
||||
@@ -278,6 +294,7 @@ export class CompileHandler {
|
||||
return createdCompilers.map(compiler => compiler.getInfo());
|
||||
} catch (err) {
|
||||
logger.error('Exception while processing compilers:', err);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,12 +29,15 @@ import {CompilationQueue} from '../compilation-queue.js';
|
||||
import {logger} from '../logger.js';
|
||||
import {SentryCapture} from '../sentry.js';
|
||||
|
||||
import {ICompileHandler} from './compile.interfaces.js';
|
||||
|
||||
export class HealthCheckHandler {
|
||||
public readonly handle: (req: any, res: any) => Promise<void>;
|
||||
|
||||
constructor(
|
||||
private readonly compilationQueue: CompilationQueue,
|
||||
private readonly filePath: any,
|
||||
private readonly compileHandler: ICompileHandler,
|
||||
) {
|
||||
this.handle = this._handle.bind(this);
|
||||
}
|
||||
@@ -52,6 +55,12 @@ export class HealthCheckHandler {
|
||||
*/
|
||||
await this.compilationQueue.enqueue(async () => {}, {highPriority: true});
|
||||
|
||||
if (!this.compileHandler.hasLanguages()) {
|
||||
logger.error(`*** HEALTH CHECK FAILURE: no languages/compilers detected`);
|
||||
res.status(500).end();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.filePath) {
|
||||
res.send('Everything is awesome');
|
||||
return;
|
||||
|
||||
@@ -35,9 +35,12 @@ describe('Health checks', () => {
|
||||
let compilationQueue;
|
||||
|
||||
beforeEach(() => {
|
||||
const compileHandlerMock = {
|
||||
hasLanguages: () => true,
|
||||
};
|
||||
compilationQueue = new CompilationQueue(1, 0, 0);
|
||||
app = express();
|
||||
app.use('/hc', new HealthCheckHandler(compilationQueue, '').handle);
|
||||
app.use('/hc', new HealthCheckHandler(compilationQueue, '', compileHandlerMock).handle);
|
||||
});
|
||||
|
||||
it('should respond with OK', async () => {
|
||||
@@ -54,15 +57,36 @@ describe('Health checks', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Health checks without lang/comp', () => {
|
||||
let app;
|
||||
let compilationQueue;
|
||||
|
||||
beforeEach(() => {
|
||||
const compileHandlerMock = {
|
||||
hasLanguages: () => false,
|
||||
};
|
||||
compilationQueue = new CompilationQueue(1, 0, 0);
|
||||
app = express();
|
||||
app.use('/hc', new HealthCheckHandler(compilationQueue, '', compileHandlerMock).handle);
|
||||
});
|
||||
|
||||
it('should respond with error', async () => {
|
||||
await request(app).get('/hc').expect(500);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Health checks on disk', () => {
|
||||
let app;
|
||||
|
||||
beforeAll(() => {
|
||||
const compileHandlerMock = {
|
||||
hasLanguages: () => true,
|
||||
};
|
||||
const compilationQueue = new CompilationQueue(1, 0, 0);
|
||||
|
||||
app = express();
|
||||
app.use('/hc', new HealthCheckHandler(compilationQueue, '/fake/.nonexist').handle);
|
||||
app.use('/hc2', new HealthCheckHandler(compilationQueue, '/fake/.health').handle);
|
||||
app.use('/hc', new HealthCheckHandler(compilationQueue, '/fake/.nonexist', compileHandlerMock).handle);
|
||||
app.use('/hc2', new HealthCheckHandler(compilationQueue, '/fake/.health', compileHandlerMock).handle);
|
||||
|
||||
mockfs({
|
||||
'/fake': {
|
||||
|
||||
Reference in New Issue
Block a user