Ensure MinimalFolder remote open forces closed on hard errors
Minimal folder should force a folder closed when an error occurrs that it isn't going to be able to recover from.
This commit is contained in:
parent
b0f85b3af8
commit
46bb4d1b6c
3 changed files with 61 additions and 44 deletions
|
|
@ -960,12 +960,18 @@ private class Geary.ImapEngine.MinimalFolder : Geary.Folder, Geary.FolderSupport
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
} catch (Error err) {
|
} catch (Error err) {
|
||||||
debug("Other error: %s", err.message);
|
ErrorContext context = new ErrorContext(err);
|
||||||
// Notify that there was a connection error, but don't
|
if (is_unrecoverable_failure(err)) {
|
||||||
// force the folder closed, since it might come good again
|
debug("Unrecoverable failure opening remote, forcing closed: %s",
|
||||||
// if the user fixes an auth problem or the network comes
|
context.format_full_error());
|
||||||
// back or whatever.
|
yield force_close(
|
||||||
notify_open_failed(Folder.OpenFailed.REMOTE_ERROR, err);
|
CloseReason.LOCAL_CLOSE, CloseReason.REMOTE_ERROR
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
debug("Recoverable error opening remote: %s",
|
||||||
|
context.format_full_error());
|
||||||
|
notify_open_failed(Folder.OpenFailed.REMOTE_ERROR, err);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -519,11 +519,11 @@ private class Geary.ImapEngine.ReplayQueue : Geary.BaseObject {
|
||||||
} catch (Error replay_err) {
|
} catch (Error replay_err) {
|
||||||
debug("Replay remote error for %s on %s: %s (%s)", op.to_string(), to_string(),
|
debug("Replay remote error for %s on %s: %s (%s)", op.to_string(), to_string(),
|
||||||
replay_err.message, op.on_remote_error.to_string());
|
replay_err.message, op.on_remote_error.to_string());
|
||||||
|
|
||||||
// If a hard failure and operation allows remote replay and not closing,
|
// If a recoverable failure and operation allows
|
||||||
// re-schedule now
|
// remote replay and not closing, re-schedule now
|
||||||
if ((op.on_remote_error == ReplayOperation.OnError.RETRY)
|
if ((op.on_remote_error == ReplayOperation.OnError.RETRY)
|
||||||
&& is_hard_failure(replay_err)
|
&& !is_unrecoverable_failure(replay_err)
|
||||||
&& state == State.OPEN) {
|
&& state == State.OPEN) {
|
||||||
debug("Schedule op retry %s on %s", op.to_string(), to_string());
|
debug("Schedule op retry %s on %s", op.to_string(), to_string());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,40 +6,51 @@
|
||||||
|
|
||||||
namespace Geary.ImapEngine {
|
namespace Geary.ImapEngine {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A hard failure is defined as one due to hardware or connectivity issues, where a soft failure
|
* Determines if retrying an operation might succeed or not.
|
||||||
* is due to software reasons, like credential failure or protocol violation.
|
*
|
||||||
*/
|
* A recoverable failure is defined as one that may not occur
|
||||||
private static bool is_hard_failure(Error err) {
|
* again if the operation that caused it is retried, without
|
||||||
// CANCELLED is not a hard error
|
* needing to make some change in the mean time. For example,
|
||||||
if (err is IOError.CANCELLED)
|
* recoverable failures may occur due to transient network
|
||||||
return false;
|
* connectivity issues or server rate limiting. On the other hand,
|
||||||
|
* an unrecoverable failure is due to some problem that will not
|
||||||
|
* succeed if tried again unless some action is taken, such as
|
||||||
|
* authentication failures, protocol parsing errors, and so on.
|
||||||
|
*/
|
||||||
|
private static bool is_unrecoverable_failure(GLib.Error err) {
|
||||||
|
return !(
|
||||||
|
err is EngineError.SERVER_UNAVAILABLE ||
|
||||||
|
err is IOError.BROKEN_PIPE ||
|
||||||
|
err is IOError.BUSY ||
|
||||||
|
err is IOError.CONNECTION_CLOSED ||
|
||||||
|
err is IOError.NOT_CONNECTED ||
|
||||||
|
err is IOError.TIMED_OUT ||
|
||||||
|
err is ImapError.NOT_CONNECTED ||
|
||||||
|
err is ImapError.TIMED_OUT ||
|
||||||
|
err is ImapError.UNAVAILABLE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Treat other errors -- most likely IOErrors -- as hard failures
|
/**
|
||||||
if (!(err is ImapError) && !(err is EngineError))
|
* Determines if an error was caused by the remote host or not.
|
||||||
return true;
|
*/
|
||||||
|
private static bool is_remote_error(GLib.Error err) {
|
||||||
return err is ImapError.NOT_CONNECTED
|
return (
|
||||||
|| err is ImapError.TIMED_OUT
|
err is EngineError.NOT_FOUND ||
|
||||||
|| err is ImapError.SERVER_ERROR
|
err is EngineError.SERVER_UNAVAILABLE ||
|
||||||
|| err is EngineError.SERVER_UNAVAILABLE;
|
err is IOError.CONNECTION_CLOSED ||
|
||||||
}
|
err is IOError.CONNECTION_REFUSED ||
|
||||||
|
err is IOError.HOST_UNREACHABLE ||
|
||||||
/**
|
err is IOError.MESSAGE_TOO_LARGE ||
|
||||||
* Determines if this IOError related to a remote host or not.
|
err is IOError.NETWORK_UNREACHABLE ||
|
||||||
*/
|
err is IOError.NOT_CONNECTED ||
|
||||||
private static bool is_remote_error(GLib.Error err) {
|
err is IOError.PROXY_AUTH_FAILED ||
|
||||||
return err is ImapError
|
err is IOError.PROXY_FAILED ||
|
||||||
|| err is IOError.CONNECTION_CLOSED
|
err is IOError.PROXY_NEED_AUTH ||
|
||||||
|| err is IOError.CONNECTION_REFUSED
|
err is IOError.PROXY_NOT_ALLOWED ||
|
||||||
|| err is IOError.HOST_UNREACHABLE
|
err is ImapError
|
||||||
|| err is IOError.MESSAGE_TOO_LARGE
|
);
|
||||||
|| err is IOError.NETWORK_UNREACHABLE
|
}
|
||||||
|| err is IOError.NOT_CONNECTED
|
|
||||||
|| err is IOError.PROXY_AUTH_FAILED
|
|
||||||
|| err is IOError.PROXY_FAILED
|
|
||||||
|| err is IOError.PROXY_NEED_AUTH
|
|
||||||
|| err is IOError.PROXY_NOT_ALLOWED;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue