@comunica/actor-init-query 2.3.0 → 2.3.1-alpha.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -17,6 +17,10 @@
|
|
|
17
17
|
{
|
|
18
18
|
"@id": "caiq:components/HttpServiceSparqlEndpoint.jsonld#IQueryBody__member_value",
|
|
19
19
|
"memberFieldName": "value"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"@id": "caiq:components/HttpServiceSparqlEndpoint.jsonld#IQueryBody__member_context",
|
|
23
|
+
"memberFieldName": "context"
|
|
20
24
|
}
|
|
21
25
|
],
|
|
22
26
|
"constructorArguments": []
|
|
@@ -51,6 +55,10 @@
|
|
|
51
55
|
"@id": "caiq:components/HttpServiceSparqlEndpoint.jsonld#IHttpServiceSparqlEndpointArgs__member_freshWorkerPerQuery",
|
|
52
56
|
"memberFieldName": "freshWorkerPerQuery"
|
|
53
57
|
},
|
|
58
|
+
{
|
|
59
|
+
"@id": "caiq:components/HttpServiceSparqlEndpoint.jsonld#IHttpServiceSparqlEndpointArgs__member_contextOverride",
|
|
60
|
+
"memberFieldName": "contextOverride"
|
|
61
|
+
},
|
|
54
62
|
{
|
|
55
63
|
"@id": "caiq:components/HttpServiceSparqlEndpoint.jsonld#IHttpServiceSparqlEndpointArgs__member_moduleRootPath",
|
|
56
64
|
"memberFieldName": "moduleRootPath"
|
|
@@ -21,6 +21,7 @@ export declare class HttpServiceSparqlEndpoint {
|
|
|
21
21
|
readonly workers: number;
|
|
22
22
|
readonly invalidateCacheBeforeQuery: boolean;
|
|
23
23
|
readonly freshWorkerPerQuery: boolean;
|
|
24
|
+
readonly contextOverride: boolean;
|
|
24
25
|
lastQueryId: number;
|
|
25
26
|
constructor(args: IHttpServiceSparqlEndpointArgs);
|
|
26
27
|
/**
|
|
@@ -108,6 +109,7 @@ export declare class HttpServiceSparqlEndpoint {
|
|
|
108
109
|
export interface IQueryBody {
|
|
109
110
|
type: 'query' | 'void';
|
|
110
111
|
value: string;
|
|
112
|
+
context: Record<string, any> | undefined;
|
|
111
113
|
}
|
|
112
114
|
export interface IHttpServiceSparqlEndpointArgs extends IDynamicQueryEngineOptions {
|
|
113
115
|
context?: any;
|
|
@@ -116,6 +118,7 @@ export interface IHttpServiceSparqlEndpointArgs extends IDynamicQueryEngineOptio
|
|
|
116
118
|
workers?: number;
|
|
117
119
|
invalidateCacheBeforeQuery?: boolean;
|
|
118
120
|
freshWorkerPerQuery?: boolean;
|
|
121
|
+
contextOverride?: boolean;
|
|
119
122
|
moduleRootPath: string;
|
|
120
123
|
defaultConfigPath: string;
|
|
121
124
|
}
|
|
@@ -25,6 +25,7 @@ class HttpServiceSparqlEndpoint {
|
|
|
25
25
|
this.workers = args.workers ?? 1;
|
|
26
26
|
this.invalidateCacheBeforeQuery = Boolean(args.invalidateCacheBeforeQuery);
|
|
27
27
|
this.freshWorkerPerQuery = Boolean(args.freshWorkerPerQuery);
|
|
28
|
+
this.contextOverride = Boolean(args.contextOverride);
|
|
28
29
|
this.engine = new __1.QueryEngineFactoryBase(args.moduleRootPath, args.defaultConfigPath, actorInitQuery => new __1.QueryEngineBase(actorInitQuery)).create(args);
|
|
29
30
|
}
|
|
30
31
|
/**
|
|
@@ -93,6 +94,7 @@ class HttpServiceSparqlEndpoint {
|
|
|
93
94
|
}
|
|
94
95
|
const invalidateCacheBeforeQuery = args.invalidateCache;
|
|
95
96
|
const freshWorkerPerQuery = args.freshWorker;
|
|
97
|
+
const contextOverride = args.contextOverride;
|
|
96
98
|
const port = args.port;
|
|
97
99
|
const timeout = args.timeout * 1000;
|
|
98
100
|
const workers = args.workers;
|
|
@@ -104,6 +106,7 @@ class HttpServiceSparqlEndpoint {
|
|
|
104
106
|
context,
|
|
105
107
|
invalidateCacheBeforeQuery,
|
|
106
108
|
freshWorkerPerQuery,
|
|
109
|
+
contextOverride,
|
|
107
110
|
moduleRootPath,
|
|
108
111
|
mainModulePath: moduleRootPath,
|
|
109
112
|
port,
|
|
@@ -138,8 +141,14 @@ class HttpServiceSparqlEndpoint {
|
|
|
138
141
|
// Respawn crashed workers
|
|
139
142
|
worker.once('exit', (code, signal) => {
|
|
140
143
|
if (!worker.exitedAfterDisconnect) {
|
|
141
|
-
|
|
142
|
-
|
|
144
|
+
if (code === 9 || signal === 'SIGKILL') {
|
|
145
|
+
stderr.write(`Worker ${worker.process.pid} forcefully killed with ${code || signal}. Killing main process as well.\n`);
|
|
146
|
+
cluster.disconnect();
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
stderr.write(`Worker ${worker.process.pid} died with ${code || signal}. Starting new worker.\n`);
|
|
150
|
+
cluster.fork();
|
|
151
|
+
}
|
|
143
152
|
}
|
|
144
153
|
});
|
|
145
154
|
// Handle worker timeouts
|
|
@@ -147,9 +156,9 @@ class HttpServiceSparqlEndpoint {
|
|
|
147
156
|
worker.on('message', ({ type, queryId }) => {
|
|
148
157
|
if (type === 'start') {
|
|
149
158
|
workerTimeouts[queryId] = setTimeout(() => {
|
|
150
|
-
stderr.write(`Worker ${worker.process.pid} timed out for query ${queryId}.\n`);
|
|
151
159
|
try {
|
|
152
160
|
if (worker.isConnected()) {
|
|
161
|
+
stderr.write(`Worker ${worker.process.pid} timed out for query ${queryId}.\n`);
|
|
153
162
|
worker.send('shutdown');
|
|
154
163
|
}
|
|
155
164
|
}
|
|
@@ -209,6 +218,19 @@ class HttpServiceSparqlEndpoint {
|
|
|
209
218
|
process.exit(15);
|
|
210
219
|
}
|
|
211
220
|
});
|
|
221
|
+
// Catch global errors, and cleanly close open connections
|
|
222
|
+
process.on('uncaughtException', async (error) => {
|
|
223
|
+
stderr.write(`Terminating worker ${process.pid} with ${openConnections.size} open connections due to uncaught exception.\n`);
|
|
224
|
+
stderr.write(error.stack);
|
|
225
|
+
// Stop new connections from being accepted
|
|
226
|
+
server.close();
|
|
227
|
+
// Close all open connections
|
|
228
|
+
for (const connection of openConnections) {
|
|
229
|
+
await new Promise(resolve => connection.end('!ERROR!', resolve));
|
|
230
|
+
}
|
|
231
|
+
// Kill the worker once the connections have been closed
|
|
232
|
+
process.exit(15);
|
|
233
|
+
});
|
|
212
234
|
}
|
|
213
235
|
/**
|
|
214
236
|
* Handles an HTTP request.
|
|
@@ -258,7 +280,7 @@ class HttpServiceSparqlEndpoint {
|
|
|
258
280
|
case 'GET':
|
|
259
281
|
// eslint-disable-next-line no-case-declarations
|
|
260
282
|
const queryValue = requestUrl.query.query;
|
|
261
|
-
queryBody = queryValue ? { type: 'query', value: queryValue } : undefined;
|
|
283
|
+
queryBody = queryValue ? { type: 'query', value: queryValue, context: undefined } : undefined;
|
|
262
284
|
// eslint-disable-next-line no-case-declarations
|
|
263
285
|
const headOnly = request.method === 'HEAD';
|
|
264
286
|
await this.writeQueryResult(engine, stdout, stderr, request, response, queryBody, mediaType, headOnly, true, this.lastQueryId++);
|
|
@@ -287,7 +309,10 @@ class HttpServiceSparqlEndpoint {
|
|
|
287
309
|
return this.writeServiceDescription(engine, stdout, stderr, request, response, mediaType, headOnly);
|
|
288
310
|
}
|
|
289
311
|
// Determine context
|
|
290
|
-
let context =
|
|
312
|
+
let context = {
|
|
313
|
+
...this.context,
|
|
314
|
+
...this.contextOverride ? queryBody.context : undefined,
|
|
315
|
+
};
|
|
291
316
|
if (readOnly) {
|
|
292
317
|
context = { ...context, [context_entries_1.KeysQueryOperation.readOnly.name]: readOnly };
|
|
293
318
|
}
|
|
@@ -334,7 +359,9 @@ class HttpServiceSparqlEndpoint {
|
|
|
334
359
|
const { data } = await engine.resultToString(result, mediaType);
|
|
335
360
|
data.on('error', (error) => {
|
|
336
361
|
stdout.write(`[500] Server error in results: ${error.message} \n`);
|
|
337
|
-
response.
|
|
362
|
+
if (!response.writableEnded) {
|
|
363
|
+
response.end('An internal server error occurred.\n');
|
|
364
|
+
}
|
|
338
365
|
});
|
|
339
366
|
data.pipe(response);
|
|
340
367
|
eventEmitter = data;
|
|
@@ -450,18 +477,27 @@ class HttpServiceSparqlEndpoint {
|
|
|
450
477
|
const contentType = request.headers['content-type'];
|
|
451
478
|
if (contentType) {
|
|
452
479
|
if (contentType.includes('application/sparql-query')) {
|
|
453
|
-
return resolve({ type: 'query', value: body });
|
|
480
|
+
return resolve({ type: 'query', value: body, context: undefined });
|
|
454
481
|
}
|
|
455
482
|
if (contentType.includes('application/sparql-update')) {
|
|
456
|
-
return resolve({ type: 'void', value: body });
|
|
483
|
+
return resolve({ type: 'void', value: body, context: undefined });
|
|
457
484
|
}
|
|
458
485
|
if (contentType.includes('application/x-www-form-urlencoded')) {
|
|
459
486
|
const bodyStructure = querystring.parse(body);
|
|
487
|
+
let context;
|
|
488
|
+
if (bodyStructure.context) {
|
|
489
|
+
try {
|
|
490
|
+
context = JSON.parse(bodyStructure.context);
|
|
491
|
+
}
|
|
492
|
+
catch (error) {
|
|
493
|
+
reject(new Error(`Invalid POST body with context received ('${bodyStructure.context}'): ${error.message}`));
|
|
494
|
+
}
|
|
495
|
+
}
|
|
460
496
|
if (bodyStructure.query) {
|
|
461
|
-
return resolve({ type: 'query', value: bodyStructure.query });
|
|
497
|
+
return resolve({ type: 'query', value: bodyStructure.query, context });
|
|
462
498
|
}
|
|
463
499
|
if (bodyStructure.update) {
|
|
464
|
-
return resolve({ type: 'void', value: bodyStructure.update });
|
|
500
|
+
return resolve({ type: 'void', value: bodyStructure.update, context });
|
|
465
501
|
}
|
|
466
502
|
}
|
|
467
503
|
}
|
|
@@ -53,6 +53,11 @@ class CliArgsHandlerHttp {
|
|
|
53
53
|
describe: 'Kills the worker after each query execution',
|
|
54
54
|
default: false,
|
|
55
55
|
},
|
|
56
|
+
contextOverride: {
|
|
57
|
+
type: 'boolean',
|
|
58
|
+
describe: 'If the query context can be overridden through POST requests',
|
|
59
|
+
default: false,
|
|
60
|
+
},
|
|
56
61
|
})
|
|
57
62
|
.check(args => {
|
|
58
63
|
if (args.version) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@comunica/actor-init-query",
|
|
3
|
-
"version": "2.3.0",
|
|
3
|
+
"version": "2.3.1-alpha.23.0",
|
|
4
4
|
"description": "A query init actor",
|
|
5
5
|
"lsd:module": true,
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -31,19 +31,19 @@
|
|
|
31
31
|
"lib/**/*.js"
|
|
32
32
|
],
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@comunica/actor-http-proxy": "
|
|
35
|
-
"@comunica/bus-context-preprocess": "
|
|
36
|
-
"@comunica/bus-http-invalidate": "
|
|
37
|
-
"@comunica/bus-init": "
|
|
38
|
-
"@comunica/bus-optimize-query-operation": "
|
|
39
|
-
"@comunica/bus-query-operation": "
|
|
40
|
-
"@comunica/bus-query-parse": "
|
|
41
|
-
"@comunica/bus-query-result-serialize": "
|
|
42
|
-
"@comunica/context-entries": "
|
|
43
|
-
"@comunica/core": "
|
|
44
|
-
"@comunica/logger-pretty": "
|
|
45
|
-
"@comunica/runner": "
|
|
46
|
-
"@comunica/types": "
|
|
34
|
+
"@comunica/actor-http-proxy": "2.3.1-alpha.23.0",
|
|
35
|
+
"@comunica/bus-context-preprocess": "2.3.1-alpha.23.0",
|
|
36
|
+
"@comunica/bus-http-invalidate": "2.3.1-alpha.23.0",
|
|
37
|
+
"@comunica/bus-init": "2.3.1-alpha.23.0",
|
|
38
|
+
"@comunica/bus-optimize-query-operation": "2.3.1-alpha.23.0",
|
|
39
|
+
"@comunica/bus-query-operation": "2.3.1-alpha.23.0",
|
|
40
|
+
"@comunica/bus-query-parse": "2.3.1-alpha.23.0",
|
|
41
|
+
"@comunica/bus-query-result-serialize": "2.3.1-alpha.23.0",
|
|
42
|
+
"@comunica/context-entries": "2.3.1-alpha.23.0",
|
|
43
|
+
"@comunica/core": "2.3.1-alpha.23.0",
|
|
44
|
+
"@comunica/logger-pretty": "2.3.1-alpha.23.0",
|
|
45
|
+
"@comunica/runner": "2.3.1-alpha.23.0",
|
|
46
|
+
"@comunica/types": "2.3.1-alpha.23.0",
|
|
47
47
|
"@rdfjs/types": "*",
|
|
48
48
|
"@types/yargs": "^17.0.2",
|
|
49
49
|
"asynciterator": "^3.4.2",
|
|
@@ -62,5 +62,5 @@
|
|
|
62
62
|
"browser": {
|
|
63
63
|
"./lib/index.js": "./lib/index-browser.js"
|
|
64
64
|
},
|
|
65
|
-
"gitHead": "
|
|
65
|
+
"gitHead": "4dd99fee904c64e9ef700eb5080197c4a03a36fa"
|
|
66
66
|
}
|