-
-
Notifications
You must be signed in to change notification settings - Fork 76
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Errors on source creation get lost #565
Comments
I traced it back to When I did attach However, when I did attach |
Side-note: it's not the first time we run into uncaught error issues. |
From what I discussed with @rubensworks,
IIUC, the unhandled promise rejection is expected in this snippet? Calling |
Not yet.
Not really; it's a lazy stream. Only preparatory actions will be undertaken (in this case, dereferencing the sources, which fails).
It's a bit more complex: since the stream is lazy, there is not necessarily a point where it is “ready to yield its result”; as such, we can't wait for it. Furthermore, errors can happen at any point. As such, we need to listen for (zero or more) errorss and redirect them as (zero or more) events to the bindings stream. I.e., the promise rejection should manifest as an event, since we can't wait for it because it can occur at any point. At the moment, something is not listening to the errors emitted by the |
OK and then how would that event end up triggering Another option would be if |
It does not. The result to
No time for that; it is of utmost importance that
Exactly, and it does this at the moment. It's just that one specific error does not find its way to that stream. ( |
Hm, but going back to the snippet (sorry, I wrote myEngine.query('CONSTRUCT WHERE { ?s ?p ?o }',
{ source: { value: 'https://ruben.verborgh.orgz' } })
.catch(e => console.error('error correctly caught', e)); there we do expect the error to trigger |
When something goes wrong during construction of the query: syntax error, component missing, etc.
|
Exactly. Since source URLs are dereferenced during actual query execution, the |
OK so then IIUC let's update the snippet to: const newEngine = require('@comunica/actor-init-sparql').newEngine;
const myEngine = newEngine();
myEngine.query('CONSTRUCT WHERE { ?s ?p ?o }',
{ source: { value: 'https://ruben.verborgh.orgz' } })
.then(result => {
result.quadStream.on('error', (e) => {
console.error('error correctly emitted', e);
});
result.quadStream.on('data', data => {
console.error('should not be reached, data from stream:', data);
});
}).catch(e => console.error('should not be reached, query construction error:', e)); And then there is no problem: ~/gh/comunica/comunica $ node test2.js
error correctly emitted Error: getaddrinfo ENOTFOUND ruben.verborgh.orgz
at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:60:26) {
errno: 'ENOTFOUND',
code: 'ENOTFOUND',
syscall: 'getaddrinfo',
hostname: 'ruben.verborgh.orgz'
} Or am I still missing something here? |
@michielbdejong It's probably a timing issue. While I was briefly able to reproduce what you have above, the same code currently consistently gives me:
|
@RubenVerborgh hold on, you are skipping ahead, let's first decide what the desired behaviour is. Desired behaviour, option 1:const newEngine = require('@comunica/actor-init-sparql').newEngine;
const myEngine = newEngine();
myEngine.query('CONSTRUCT WHERE { ?s ?p ?o }',
{ source: { value: 'https://ruben.verborgh.orgz' } })
.catch(e => console.error('error correctly caught', e)); Desired behaviour, option 2:const newEngine = require('@comunica/actor-init-sparql').newEngine;
const myEngine = newEngine();
myEngine.query('CONSTRUCT WHERE { ?s ?p ?o }',
{ source: { value: 'https://ruben.verborgh.orgz' } })
.then(result => {
result.quadStream.on('error', (e) => {
console.error('error correctly emitted', e);
});
result.quadStream.on('data', data => {
console.error('should not be reached, data from stream:', data);
});
}).catch(e => console.error('should not be reached, query construction error:', e)); |
Option 2, we established that above (#565 (comment)). Updated the description of the issue.
|
ok! Great, thanks. But then I can't reproduce this issue. I see this: ~/gh/comunica/comunica $ node test3.js
error correctly emitted Error: getaddrinfo ENOTFOUND ruben.verborgh.orgz
at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:60:26) {
errno: 'ENOTFOUND',
code: 'ENOTFOUND',
syscall: 'getaddrinfo',
hostname: 'ruben.verborgh.orgz'
} @rubensworks could you try on your machine? |
@michielbdejong As explained above, it is a timing issue, so you might or might not see it. Below a screenshot of two consecutive invocations, one of which works, the other fails: The error bubbles up two times: one time when preparing sources, the other when querying them. It is this second error that is caught by the code above. The timing of these errors is crucial: if source preparation is still pending while execution starts, then the error is handled by the query execution mechanism. If source preparation finishes earlier, then the error goes uncaught initially, only to surface again (and then be caught) during execution. We know that there is a bug:
|
Ah, so then how about a variation on option 2, but with a delay before consuming the stream? On my machine, this starts failing when I set the So the error occurs before the error handler has been attached to the stream. Maybe it should queue up errors in this case? Desired behaviour, option 3:const newEngine = require('@comunica/actor-init-sparql').newEngine;
const myEngine = newEngine();
myEngine.query('CONSTRUCT WHERE { ?s ?p ?o }',
{ source: { value: 'https://ruben.verborgh.orgz' } })
.then(result => {
setTimeout(() => {
result.quadStream.on('error', (e) => {
console.error('error correctly emitted', e);
});
result.quadStream.on('data', data => {
console.error('should not be reached, data from stream:', data);
});
}, 1000);
},
e => console.error('should not be reached, query construction error:', e)); |
I was almost on board with that and had already edited the issue… but I realized it's slightly more subtle:
That's not the case; I added a logging statement to the code to make that explicit.
My understanding of what's happening on
The error from 2 is the one we pick up. The error from 1 is lost if 1 finished before 2. Note that losing the error is not because of the error handler that we attach; the logging statement shows that this one is attached on time. The problem is that: Now a) I can solve easily: after comunica/packages/actor-rdf-resolve-quad-pattern-hypermedia/lib/LinkedRdfSourcesAsyncRdfIterator.ts Line 112 in f6330c4
source.then(source => source.on('error', e => this.emit('error', e))) .
My problem with b) is that I don't know who should be listening for it. Whomever should be listening, is responsible for taking the error emitted by
No, it is the task of whoever calls |
Very insightful summary! That's very helpful, I'll debug it further next week. |
Sorry, didn't find time to work on this more, and have lots of other things to do in the near future. I did just read https://nodesource.com/blog/understanding-streams-in-nodejs/ which mentions the |
Oh TIL, looks like a useful thing to investigate indeed.
Setting our min Node version to 10 shouldn't be a major problem. |
It looks like this is not fully fixed yet: LDflex/Query-Solid#30 (comment) Can be reproduced via the JS API, by for example querying over |
Key is that all bases are covered = all rejections are caught. For example: https://github.com/LDflex/LDflex-Comunica/blob/v3.4.0/src/ComunicaEngine.js#L17 What's important here is that, on this specific line, we don't care about handling the error, because it will bubble up anyway on https://github.com/LDflex/LDflex-Comunica/blob/v3.4.0/src/ComunicaEngine.js#L28 I.e., this is where promises are different from traditional |
Maybe we even want to have a reusable export function silenceRejection(promise) {
promise.catch(() => null);
return promise;
} to make the intent more clear. |
This was a false-positive, it was a bug in my debugging environment that caused unhandled promise rejections. In any case, I've discovered some minor problems related to this, so the effort was not useless: |
Issue type:
Description:
Expect this error to be caught by the
error
event, but it slips away as a rejected promise.This is a specific case of #103 and the direct cause of LDflex/Query-Solid#30.
Environment:
Crash log:
The text was updated successfully, but these errors were encountered: