NotionCommotion Posted April 12, 2017 Share Posted April 12, 2017 How do I catch the second exception? <?php require '../vendor/autoload.php'; $ErrorServer=new \DataLogger\Server\ErrorServer(); $ErrorServer->start(); <?php namespace DataLogger\Server; class ErrorServer { public function start() { try { throw new \Exception ('This error is caught.'); } catch(\Exception $e) { echo($e->getMessage().PHP_EOL); } $loop = \React\EventLoop\Factory::create(); $socket = new \React\Socket\Server($loop); $socket->on('connection', function (\React\Socket\ConnectionInterface $stream) use($loop) { try { $loop->addPeriodicTimer(2, function() { throw new \Exception('This error is uncaught'); }); } catch(\Exception $e) { echo($e->getMessage().PHP_EOL); } }); $socket->listen(1337, '0.0.0.0'); $loop->run(); } } This error is caught. Fatal error: Uncaught exception 'Exception' with message 'This error is uncaught' in /var/www/datalogger/src/server/ErrorServer.php:19 Stack trace: #0 [internal function]: DataLogger\Server\ErrorServer->DataLogger\Server\{closure}(Object(React\EventLoop\Timer\Timer)) #1 /var/www/datalogger/vendor/react/event-loop/src/Timer/Timers.php(90): call_user_func(Object(Closure), Object(React\EventLoop\Timer\Timer)) #2 /var/www/datalogger/vendor/react/event-loop/src/StreamSelectLoop.php(177): React\EventLoop\Timer\Timers->tick() #3 /var/www/datalogger/src/server/ErrorServer.php(27): React\EventLoop\StreamSelectLoop->run() #4 /var/www/datalogger/public/error.php(4): DataLogger\Server\ErrorServer->start() #5 {main} thrown in /var/www/datalogger/src/server/ErrorServer.php on line 19 Quote Link to comment Share on other sites More sharing options...
Jacques1 Posted April 12, 2017 Share Posted April 12, 2017 This has nothing to do with namespaces, as you can tell from the fact that the first exception does get caught. It has to do with understanding exceptions. A try statement only catches exceptions which are thrown during execution of the enclosed code. It does not and cannot trace every problem which is somehow indirectly related to this code block. So catching exceptions from the registered callback is the job of the caller (in your case the Timer class) or one of the caller's callers (e. g. the loop). Quote Link to comment Share on other sites More sharing options...
requinix Posted April 12, 2017 Share Posted April 12, 2017 Exceptions bubble up directly through the call stack, so you can look at the call stack to see where you could catch it. Besides in main, the only place where you could stick a try/catch would be /var/www/datalogger/src/server/ErrorServer.php(27): React\EventLoop\StreamSelectLoop->run()around that. Quote Link to comment Share on other sites More sharing options...
NotionCommotion Posted April 12, 2017 Author Share Posted April 12, 2017 After giving it a little thought, I came to the same conclusion. Is there a way to catch exceptions (and standard errors as well for that mater) globally, and determine within that handler whether a client connection is defined within the scope? Quote Link to comment Share on other sites More sharing options...
NotionCommotion Posted April 12, 2017 Author Share Posted April 12, 2017 Exceptions bubble up directly through the call stack, so you can look at the call stack to see where you could catch it. Besides in main, the only place where you could stick a try/catch would be /var/www/datalogger/src/server/ErrorServer.php(27): React\EventLoop\StreamSelectLoop->run()around that. Same question. I just realized my original code didn’t show the $stream->close() that I meant to show. My desire is to close any client connection which is related to the exception. I can put the try/catch around run(), but how can I have access to $stream? Quote Link to comment Share on other sites More sharing options...
requinix Posted April 12, 2017 Share Posted April 12, 2017 Is there a way to catch exceptions (and standard errors as well for that mater) globally, and determine within that handler whether a client connection is defined within the scope?Well... you shouldn't. You can catch exceptions globally but there's no way to recover at that point - the call stack is totally unwound and you can't get back to where you were before. Really, the global exception handler should only be for preventing your script from barfing a white page of death upon an uncaught exception and instead doing something like logging the exception and showing a 500 page. Same question. I just realized my original code didn’t show the $stream->close() that I meant to show. My desire is to close any client connection which is related to the exception. I can put the try/catch around run(), but how can I have access to $stream?You can't do it in the code you've shown: the onconnection stuff only happens once (useless to try to catch an exception there) and I believe the periodic timer runs separately from connection handling (exceptions thrown in there have nothing to do with connections). You have to catch the exception between the place that does the work and React's code. That may mean introducing a layer: // before $react->on("event", function() { // work... // exceptions thrown here cannot be reliably caught and dealt with }); // after function do_the_work() { // work... // exceptions thrown here cannot be caught in here (without refactoring)... } $react->on("event", function() { try { do_the_work(); // (some sort of function or method call) } catch (\Exception $e) { // ...but could be caught here } });The point is that the event handler adds a layer between your working code (can't add a try/catch, presumably) and the React code (can't add a try/catch) where you can add a try/catch. Quote Link to comment Share on other sites More sharing options...
NotionCommotion Posted April 13, 2017 Author Share Posted April 13, 2017 Well... you shouldn't. You can catch exceptions globally but there's no way to recover at that point - the call stack is totally unwound and you can't get back to where you were before. Really, the global exception handler should only be for preventing your script from barfing a white page of death upon an uncaught exception and instead doing something like logging the exception and showing a 500 page. You can't do it in the code you've shown: the onconnection stuff only happens once (useless to try to catch an exception there) and I believe the periodic timer runs separately from connection handling (exceptions thrown in there have nothing to do with connections). The script is a sockets server and not a HTTP server. If something real bad happened, the desired next step is not a 500 page, but to kill the process and restart it. Probably need to use exec(), right? And the onconnection stuff will happen more than once as multiple clients can connect. If an exception occurred due to a specific client, I don't wish to stop the server, but just log the issue and close the connection to that client. $react->on("event", function() { try { do_the_work(); // (some sort of function or method call) } catch (\Exception $e) { // ...but could be caught here } }); Thanks requnix, Your solution to place the try/catch blocks within each on event closure will work. I might need a couple of them, but not too many. Quote Link to comment Share on other sites More sharing options...
requinix Posted April 14, 2017 Share Posted April 14, 2017 Socket servers shouldn't abruptly die either. Anything "server" should not die. Do whatever you can to make that not happen. Quote Link to comment Share on other sites More sharing options...
NotionCommotion Posted April 14, 2017 Author Share Posted April 14, 2017 Socket servers shouldn't abruptly die either. Anything "server" should not die. Do whatever you can to make that not happen. Sure, but what if something really bad happens? Isn't reincarnation better than nothing? Quote Link to comment Share on other sites More sharing options...
requinix Posted April 14, 2017 Share Posted April 14, 2017 Well yes, you need a backup in case of what's today's excuse... multicasts on broken packets, but that's not a reason to avoid trying to recover. (Not to say that's what you're doing.) Quote Link to comment Share on other sites More sharing options...
NotionCommotion Posted April 14, 2017 Author Share Posted April 14, 2017 Yes, my desire is to try to recovery, and thank you for acknowledging so. Broken packets has been identified as a risk, and has a mitigation plan in place. But whether or not I have a good excuse, dead servers are not a good thing, there are always unforeseen circumstances, and we all need a global backup plan. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.