diff --git a/src/servers/model/server/query.ts b/src/servers/model/server/query.ts index 13a1816935f010f35d9627c23a576133f631fe05..bba3bf51e541fd67ca8bdbb020c13bf518d10444 100644 --- a/src/servers/model/server/query.ts +++ b/src/servers/model/server/query.ts @@ -31,43 +31,59 @@ export async function resolveJob(job: Job, writer: Writer) { const wrappedStructure = await getStructure(job); - perf.start('query'); - // TODO: encode errors that happen past this point as CIF rather than just 404 - const structure = job.queryDefinition.structureTransform - ? await job.queryDefinition.structureTransform(job.normalizedParams, wrappedStructure.structure) - : wrappedStructure.structure; - const query = job.queryDefinition.query(job.normalizedParams, structure); - const result = StructureSelection.unionStructure(StructureQuery.run(query, structure, Config.maxQueryTimeInMs)); - perf.end('query'); - - ConsoleLogger.logId(job.id, 'Query', 'Query finished.'); + let startedWriting = false; + try { + const encoder = CifWriter.createEncoder({ binary: job.responseFormat.isBinary, encoderName: `ModelServer ${Version}` }); + perf.start('query'); + const structure = job.queryDefinition.structureTransform + ? await job.queryDefinition.structureTransform(job.normalizedParams, wrappedStructure.structure) + : wrappedStructure.structure; + const query = job.queryDefinition.query(job.normalizedParams, structure); + const result = await StructureSelection.unionStructure(StructureQuery.run(query, structure, Config.maxQueryTimeInMs)); + perf.end('query'); + + ConsoleLogger.logId(job.id, 'Query', 'Query finished.'); + + perf.start('encode'); + encoder.startDataBlock(structure.units[0].model.label.toUpperCase()); + encoder.writeCategory(_model_server_result, [job]); + encoder.writeCategory(_model_server_params, [job]); + + // encoder.setFilter(mmCIF_Export_Filters.onlyPositions); + encode_mmCIF_categories(encoder, result); + // encoder.setFilter(); + perf.end('encode'); + + ConsoleLogger.logId(job.id, 'Query', 'Encoded.'); + + const stats: Stats = { + structure: wrappedStructure, + queryTimeMs: perf.time('query'), + encodeTimeMs: perf.time('encode') + }; + + encoder.writeCategory(_model_server_stats, [stats]); + encoder.encode(); + startedWriting = true; + encoder.writeTo(writer); + ConsoleLogger.logId(job.id, 'Query', 'Written.'); + } catch (e) { + ConsoleLogger.errorId(job.id, e); + if (!startedWriting) { + doError(job, writer, e); + } else { + ConsoleLogger.errorId(job.id, 'Error was not relayed to the user because it happened during "write".'); + } + } +} +function doError(job: Job, writer: Writer, e: any) { const encoder = CifWriter.createEncoder({ binary: job.responseFormat.isBinary, encoderName: `ModelServer ${Version}` }); - - perf.start('encode'); - encoder.startDataBlock(structure.units[0].model.label.toUpperCase()); encoder.writeCategory(_model_server_result, [job]); encoder.writeCategory(_model_server_params, [job]); - - // encoder.setFilter(mmCIF_Export_Filters.onlyPositions); - encode_mmCIF_categories(encoder, result); - // encoder.setFilter(); - perf.end('encode'); - - ConsoleLogger.logId(job.id, 'Query', 'Encoded.'); - - const stats: Stats = { - structure: wrappedStructure, - queryTimeMs: perf.time('query'), - encodeTimeMs: perf.time('encode') - }; - - encoder.writeCategory(_model_server_stats, [stats]); + encoder.writeCategory(_model_server_error, ['' + e]); encoder.encode(); - encoder.writeTo(writer); - - ConsoleLogger.logId(job.id, 'Query', 'Written.'); } const maxTime = Config.maxQueryTimeInMs; @@ -88,7 +104,7 @@ function int32<T>(name: string, value: (data: T) => number): CifField<number, T> return CifField.int(name, (i, d) => value(d)); } -const _model_server_result_fields: CifField<number, Job>[] = [ +const _model_server_result_fields: CifField<any, Job>[] = [ string<Job>('job_id', ctx => '' + ctx.id), string<Job>('datetime_utc', ctx => ctx.datetime_utc), string<Job>('server_version', ctx => Version), @@ -102,6 +118,10 @@ const _model_server_params_fields: CifField<number, string[]>[] = [ string<string[]>('value', (ctx, i) => ctx[i][1]) ]; +const _model_server_error_fields: CifField<number, string>[] = [ + string<string>('message', (ctx, i) => ctx) +]; + const _model_server_stats_fields: CifField<number, Stats>[] = [ int32<Stats>('io_time_ms', ctx => ctx.structure.info.readTime | 0), int32<Stats>('parse_time_ms', ctx => ctx.structure.info.parseTime | 0), @@ -110,12 +130,16 @@ const _model_server_stats_fields: CifField<number, Stats>[] = [ int32<Stats>('encode_time_ms', ctx => ctx.encodeTimeMs | 0) ]; - const _model_server_result: CifWriter.Category<Job> = { name: 'model_server_result', instance: (job) => ({ data: job, fields: _model_server_result_fields, rowCount: 1 }) }; +const _model_server_error: CifWriter.Category<string> = { + name: 'model_server_error', + instance: (message) => ({ data: message, fields: _model_server_error_fields, rowCount: 1 }) +}; + const _model_server_params: CifWriter.Category<Job> = { name: 'model_server_params', instance(job) { diff --git a/src/servers/model/server/structure-wrapper.ts b/src/servers/model/server/structure-wrapper.ts index 8ad9885c09aaf5aa8d86ded7580807197b3b3985..2190b602ab3d752a2d9427ce9a16e45c341d574f 100644 --- a/src/servers/model/server/structure-wrapper.ts +++ b/src/servers/model/server/structure-wrapper.ts @@ -13,6 +13,7 @@ import * as util from 'util' import * as fs from 'fs' import * as zlib from 'zlib' import { Job } from './jobs'; +import { ConsoleLogger } from 'mol-util/console-logger'; require('util.promisify').shim(); @@ -87,7 +88,14 @@ async function readStructure(key: string, sourceId: string, entryId: string) { if (!fs.existsSync(filename)) throw new Error(`Could not map '${key}' to an existing file.`); perf.start('read'); - const data = await readFile(filename); + let data; + try { + data = await readFile(filename); + } catch (e) { + ConsoleLogger.error(key, '' + e); + throw new Error(`Could not read the file for '${key}' from disk.`); + } + perf.end('read'); perf.start('parse'); const frame = (await parseCif(data)).blocks[0]; diff --git a/src/servers/model/server/web-api.ts b/src/servers/model/server/web-api.ts index d10563772d2d63b5296416839259b66eb28b91d2..61eee63eb68b502e932cd31ea5fb0a641fd442a6 100644 --- a/src/servers/model/server/web-api.ts +++ b/src/servers/model/server/web-api.ts @@ -69,12 +69,12 @@ async function processNextJob() { try { writer.writeHeader(job.responseFormat.isBinary); await resolveJob(job, writer); - writer.end(); } catch (e) { ConsoleLogger.errorId(job.id, '' + e); // TODO: add some error? writer.doError(404); } finally { + writer.end(); setImmediate(processNextJob); } }