-
Notifications
You must be signed in to change notification settings - Fork 115
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
Unhandled Exception #51
Comments
The issue most likely happens in the method below: private void IdleLoop() That's due to the stack trace below: Framework Version: v4.0.30319 |
More information from IdleLoop(): Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. |
The main problem is, I can't handle the exception in my code. Since its not running in the same thread. There should probably be a way to let the caller handle a closed connection. |
Well, there is a way to handle an exception thrown from another child thread. However, I believe that throwing that exception is unnecessary unless the code developer says otherwise. I commented out "throw" keyword and compiled the code. Since then, the code has been working well without any surprised shutdown. |
Ok, I'll try that. However, I'm not sure why you would not want to handle an exception if the connection was closed. |
If the connection is closed, wouldn't that while(true) loop re-initialize the stream and read data moving forward? Why other types are inner exceptions are digested and not thrown while any other types must be thrown out? What would be the difference? What would be your suggestion? Am I missing something? |
I was not aware that the stream will be reinitialized. I don't see the line of code that will do that. |
string response = GetResponse(); will try to read the stream again. However what would be the difference between the socket exception, or thread exception and other types of exceptions. All of them will somehow terminate the connection. What I don't understand is that why only two types of inner exceptions are handled gracefully while the other ones must be bubbled up? |
If the host closes the connection then it won't be successful. |
I know, I think we have to wait for the developer to address it. |
If the connection is closed, for whatever reason, then the connection needs to be reestablished. So for any kind of connection error, the client needs to be restarted. If there is anything that can not be handled internally, the errors should bubble up, and handled in user code. |
Allowing it to bubble up does not send the exception back to the users code, as its handled in a different thread. So where would you catch it? |
That is correct. The ImapClient code must be modified to catch the exception within it. That requires to commit (check in) a newer version of code to this GitHub project. It is impossible to catch that exception in your own code. |
How would you send an exception from a new thread back to your code? |
Well, haven't done so! A little bit googling may help. This is the 1st result that I got from google, however it may not be applicable to our case: http://stackoverflow.com/questions/1554181/exception-handling-in-threads |
The exceptions (any) must be caught and handled within the same method. There is no other way to catch it outside of the thread. If the thread was like a Task, there would be a firm workaround. |
Hello, what workaround do you propose? I'm not a fan of silently attempting to On Fri, May 3, 2013 at 12:28 PM, ArtaTechs notifications@github.com wrote:
|
The exception thrown from inside the IdleLoop thread cannot be handled in the parent thread and that will make the application shutdown unexpectedly. Therefore the throw keyword must be removed and the parent thread be signaled by raising a new event. That event must be handled such that the connection to be reestablished and idling loop begun. You are correct, the noop command has to keep the connection alive but what if the Internet connection is lost? You can test this situation by disconnecting your development laptop. |
Use AppDomain.UnhandledException and friends to be able to handle all exceptions. AddHandler AppDomain.CurrentDomain.UnhandledException, AddressOf UnhExceptionHandler
AddHandler System.Windows.Forms.Application.ThreadException, AddressOf ThrExceptionHandler But maybe the IdleLoop could raise a event containing the exception, instead of throwing a exception? |
I have no idea why, I'm net getting a message from the remote host. Trying to reconnect is probably not a good idea, as you said. The solution I'm thinking is to chain tasks. http://msdn.microsoft.com/en-us/library/dd321576.aspx The user can pass a task that can be executed in case of an exception. |
Task is a great and contemporary solution. With the current code base the fastest and more reliable solution is what I suggested in my previous post. Just my 2 cents though. |
Yes, you led me in that direction. |
I guess it would be a good idea to share the solution by whoever implements it first including myself. |
I got it to work using tasks. private Task IdleTask;
//If the cancelation is ever set, the token must be recreated and I have not done so. update to getresponse(); while (true) { Instead of starting a new thread you should start a new task. if (IdleTask != null) Change dispose to if (IdleTask != null)
Finally add to user code. task = new Action(catchExceptionHandler); static void catchExceptionHandler(Task t) Its far from perfect. |
You also have to add to Dispose() if (noopTimer != null) If not the timer will keep sending noop to a non-existing connection. |
After finally successfully running for 24 consecutive hours the gmail server sent this message |
@harlyd : by using the same GetResponse for "foreground actions" (e.g. get a message when your program needs it), and "background actions" (idle mechanism), you end up injecting means to abort a read that can be invalidated. Shouldn't you have two cancellation task sources? One for foreground actions (which remains constant, and is cancelled when you dispose), and one that is being cancelled and recreated every time the idling is started/stopped/paused/resumed. |
@ssteiner sounds right, I did have some issues. |
I wondered... I find the design choices they made with those token pretty weird (you need to pass them around, and you can't infer them inside a task you'd like to abort... looking at the syntax I figured maybe the async methods in the BCL would at least honor the token, but you've made the same experience as I - and I found a little explanation thereafter: http://stackoverflow.com/questions/20131434/cancel-networkstream-readasync-using-tcplistener Makes one wonder why they add the overload if it is pointless. |
The ImapClient now exposes the IdleError event which is raised when an exception occurs in IdleLoop. This is much like what ArtaTechs and NiKiZe suggested. I'm closing this, but feel free to create a new issue if you run into any trouble with this solution. |
I'm using the Imap client to notify me when I get a new message in gmail.
The problem I'm having is, that after a number of hours the remoter server closes the connection.
This becomes apparent in s22.imap.getresponse byte b = (byte)stream.ReadByte();
I get an unhadled exception. The message is, the connection forcibly closed by remote host.
The text was updated successfully, but these errors were encountered: