简体   繁体   中英

AMPHP throws an uncatchable MultiReasonException - Is this a bug?

I'm getting a MultiReasonException thrown during a DNS lookup as part of a AMP Socket connect call. The actual exception thrown is an NX domain, which is fine - the lookup is for a host which is down currently. The problem is I cannot catch and handle the exception - it ends up at the loop level where I am able to catch it, but it's no use at that point.

I tried to reproduce in a simple test script for posting here, but it works correctly if I just do:

Loop::run(function(){
 $res = yield \Amp\Dns\resolve("tp-link-hs110-5");
 var_dump($res);
}); 

and wrap it in a try catch I'm able to catch the DNS exception - it doesn't even throw a MultiReasonException . I think this is something to do with the fact my actual application has a lot more going on "concurrently" which means the loop actually goes off and does other stuff while waiting for the DNS request to fail ("defers" the dns lookup coroutine). This appears to cause the exception to be thrown wrapped in a MultiReasonException for some reason (there is only 1 exception listed in the Mutli in xdebug). What's more, the MultiReasonException is not thrown into my coroutine where the connect call was made, it just ends up being thrown into the Loop::run call - and this is the real problem. I cannot handle the exception here, since it's not in the calling context and could be from anywhere in the code.

Can anyone help shed any light on this, or even point me in the right direction to pin this down a little more? I'm all out of ideas. Trying to trace this thing through a massive stack full of Coroutines and Placeholder functions is a nightmare. How on Earth do you debug such things through the AMP stack?

In case anyone else has a similar problem I think I found the answer to my own question.

It's a subtlety of how the Amp stack handles exceptions. I was calling the amp function some on 1 or more promises in a high level function. This acted on a promise chain which eventually led down to a function that made a DNS lookup. When the DNS lookup failed and threw a DNS related exception (which I wasn't catching in the Promise) it percolated up the promise chain to the some, which it appears always throws a MultiReasonException even if it has only 1 promise it's acting on. This meant that the I always got a MultiReasonException which contained the DNS exception. This would be fine, except when I looked a the stack trace for the DNS related exception, it of course did not contain any of my functions - so I could not see how it could be caught (I also did not just try to catch it at the source, which it turns out would have worked, but looked from the trace like it wouldn't).

This is because the exception is thrown during a time when amp was on a subsequent tick, and thus my code was not currently on the stack. Once the exception was thrown by code in the AMP stack, the trace in the exception is of course locked in. It would then be thrown back into my original promise (generator) which requested the lookup, where it could have been caught, but since I wasn't catching it, it got thrown all the way up to the some call, where it confused me by appearing as a MultiReasonException .

I'm not sure how coherent that is, but maybe it will help somebody. Moral of the story - don't try to be clever - just catch the relevant exception where you yield the promise that will throw it. The exception stack traces can be misleading in AMP.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM