Commit a23378b0 authored by Krzysztof Nowicki's avatar Krzysztof Nowicki Committed by Laurent Montel
Browse files

Don't clear sync state if sync error is not related to the sync itself



Quite often the sync can fail due to trivial errors like expiration of
the authentication token or exceeded request quota on the EWS
server. In such case forcing clearing of the sync state is not needed
and results in unnecessary load.

To fix this, the EWS requests can now propagate the errors received
from the EWS server so that the controller is able to determine the
reason for the failure and act accordingly.
Signed-off-by: Krzysztof Nowicki's avatarKrzysztof Nowicki <krissn@op.pl>
parent bf6170c0
......@@ -130,6 +130,7 @@ void EwsRequest::requestResult(KJob *job)
if (resp == 401 && mClient.auth()) {
mClient.auth()->notifyRequestAuthFailed();
setEwsResponseCode(EwsResponseCodeUnauthorized);
}
if (job->error() != 0) {
......
......@@ -36,3 +36,16 @@ EwsResponseCode decodeEwsResponseCode(const QString &code)
return EwsResponseCodeUnknown;
}
}
bool isEwsResponseCodeTemporaryError(EwsResponseCode code)
{
switch (code) {
case EwsResponseCodeErrorServerBusy:
/* fall through */
case EwsResponseCodeUnauthorized:
return true;
default:
return false;
}
return false;
}
......@@ -455,8 +455,9 @@ typedef enum {
} EwsEventType;
typedef enum {
EwsResponseCodeNoError,
EwsResponseCodeNoError = 0,
EwsResponseCodeErrorServerBusy,
EwsResponseCodeUnauthorized,
EwsResponseCodeUnknown,
} EwsResponseCode;
......@@ -482,3 +483,4 @@ inline bool isEwsMessageItemType(EwsItemType type)
extern const QVector<QString> ewsItemTypeNames;
EwsResponseCode decodeEwsResponseCode(const QString &code);
bool isEwsResponseCodeTemporaryError(EwsResponseCode code);
......@@ -7,7 +7,8 @@
#include "ewsfetchitemdetailjob.h"
EwsFetchItemDetailJob::EwsFetchItemDetailJob(EwsClient &client, QObject *parent, const Akonadi::Collection &collection)
: KCompositeJob(parent)
: EwsJob(parent)
, mDeletedItems(nullptr)
, mClient(client)
, mCollection(collection) // never used
{
......
......@@ -15,9 +15,10 @@
#include "ewsgetitemrequest.h"
#include "ewsid.h"
#include "ewsitem.h"
#include "ewsjob.h"
#include "ewstypes.h"
class EwsFetchItemDetailJob : public KCompositeJob
class EwsFetchItemDetailJob : public EwsJob
{
Q_OBJECT
public:
......
......@@ -214,6 +214,9 @@ void EwsFetchItemsJob::remoteItemFetchDone(KJob *job)
Q_EMIT reportPercent(qMin(totalItems * 50 / mLocalItems.size(), 50));
}
Q_EMIT reportStatus(AgentBase::Running, i18nc("@info:status", "Retrieving %1 item list (%2 items)", mCollection.name(), totalItems));
} else {
setEwsResponseCode(itemReq->ewsResponseCode());
qCWarningNC(EWSRES_LOG) << QStringLiteral("EwsFetchItemsJob: Failed remote item sync");
}
}
......@@ -423,9 +426,10 @@ void EwsFetchItemsJob::itemDetailFetchDone(KJob *job)
{
removeSubjob(job);
if (!job->error()) {
auto detailJob = qobject_cast<EwsFetchItemDetailJob *>(job);
if (detailJob) {
const auto detailJob = qobject_cast<EwsFetchItemDetailJob *>(job);
if (detailJob) {
qCWarningNC(EWSRES_LOG) << QStringLiteral("itemDetailFetchDone: ") << detailJob->error();
if (!detailJob->error()) {
const auto changedItems = detailJob->changedItems();
for (const auto &item : changedItems) {
if (item.isValid()) {
......@@ -434,15 +438,17 @@ void EwsFetchItemsJob::itemDetailFetchDone(KJob *job)
mNewItems.append(item);
}
}
}
mTotalItemsFetched = mChangedItems.size();
Q_EMIT reportPercent(50 + (mTotalItemsFetched * 50) / mTotalItemsToFetch);
mTotalItemsFetched = mChangedItems.size();
Q_EMIT reportPercent(50 + (mTotalItemsFetched * 50) / mTotalItemsToFetch);
if (subjobs().isEmpty()) {
emitResult();
if (subjobs().isEmpty()) {
emitResult();
} else {
subjobs().first()->start();
}
} else {
subjobs().first()->start();
setEwsResponseCode(detailJob->ewsResponseCode());
}
}
}
......
......@@ -324,17 +324,24 @@ void EwsResource::retrieveItems(const Collection &collection)
queueFetchItemsJob(collection, [this](EwsFetchItemsJob *fetchJob) {
auto col = fetchJob->collection();
if (fetchJob->error()) {
qCWarningNC(EWSRES_LOG) << QStringLiteral("Item fetch error:") << fetchJob->errorString() << fetchJob->error();
const auto syncState = getCollectionSyncState(fetchJob->collection());
if (!syncState.isEmpty()) {
qCDebugNC(EWSRES_LOG) << QStringLiteral("Retrying with empty state.");
// Retry with a clear sync state.
saveCollectionSyncState(col, QString());
retrieveItems(col);
qCWarningNC(EWSRES_LOG) << QStringLiteral("Item fetch error:") << fetchJob->errorString() << fetchJob->error() << fetchJob->ewsResponseCode();
if (!isEwsResponseCodeTemporaryError(fetchJob->ewsResponseCode())) {
const auto syncState = getCollectionSyncState(fetchJob->collection());
if (!syncState.isEmpty()) {
qCDebugNC(EWSRES_LOG) << QStringLiteral("Retrying with empty state.");
// Retry with a clear sync state.
saveCollectionSyncState(col, QString());
retrieveItems(col);
} else {
qCDebugNC(EWSRES_LOG) << QStringLiteral("Clean sync failed.");
// No more hope
cancelTask(i18nc("@info:status", "Failed to retrieve items"));
return;
}
} else {
qCDebugNC(EWSRES_LOG) << QStringLiteral("Clean sync failed.");
// No more hope
qCDebugNC(EWSRES_LOG) << QStringLiteral("Sync failed due to temporary error - not clearing state");
cancelTask(i18nc("@info:status", "Failed to retrieve items"));
setTemporaryOffline(reconnectTimeout());
return;
}
} else {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment