From 2c3de5fcfdb5d97ad71577b2f1fd6257743c2c51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dan=20Vr=C3=A1til?= Date: Sun, 8 Feb 2015 13:04:02 +0100 Subject: Async: improve error handling All jobs and executors now accept ErrorHandler argument which will be invoked on error. Error handling itself has been moved to Executor::exec(), so that we don't have to copy-paste the error handling code into every Executor implementation. --- async/src/async.h | 123 ++++++++++++++++++++++++++---------------------------- 1 file changed, 60 insertions(+), 63 deletions(-) (limited to 'async') diff --git a/async/src/async.h b/async/src/async.h index 336bae2..8523df3 100644 --- a/async/src/async.h +++ b/async/src/async.h @@ -33,7 +33,6 @@ /* - * TODO: error continuation on .then and others. * TODO: instead of passing the future objects callbacks could be provided for result reporting (we can still use the future object internally */ namespace Async { @@ -97,8 +96,9 @@ template class Executor : public ExecutorBase { protected: - Executor(const Private::ExecutorBasePtr &parent) + Executor(ErrorHandler errorHandler, const Private::ExecutorBasePtr &parent) : ExecutorBase(parent) + , mErrorFunc(errorHandler) , mPrevFuture(0) {} virtual ~Executor() {} @@ -116,7 +116,7 @@ template class ThenExecutor: public Executor::type, Out, In ...> { public: - ThenExecutor(ThenTask then, ErrorHandler errorHandler = ErrorHandler(), const ExecutorBasePtr &parent = ExecutorBasePtr()); + ThenExecutor(ThenTask then, ErrorHandler errorHandler, const ExecutorBasePtr &parent); void previousFutureReady(); }; @@ -124,7 +124,7 @@ template class EachExecutor : public Executor { public: - EachExecutor(EachTask each, const ExecutorBasePtr &parent); + EachExecutor(EachTask each, ErrorHandler errorHandler, const ExecutorBasePtr &parent); void previousFutureReady(); private: @@ -135,14 +135,14 @@ template class ReduceExecutor : public ThenExecutor { public: - ReduceExecutor(ReduceTask reduce, const ExecutorBasePtr &parent); + ReduceExecutor(ReduceTask reduce, ErrorHandler errorHandler, const ExecutorBasePtr &parent); }; template class SyncThenExecutor : public Executor::type, Out, In ...> { public: - SyncThenExecutor(SyncThenTask then, ErrorHandler errorHandler = ErrorHandler(), const ExecutorBasePtr &parent = ExecutorBasePtr()); + SyncThenExecutor(SyncThenTask then, ErrorHandler errorHandler, const ExecutorBasePtr &parent); void previousFutureReady(); protected: SyncThenTask mFunc; @@ -152,14 +152,14 @@ template class SyncReduceExecutor : public SyncThenExecutor { public: - SyncReduceExecutor(SyncReduceTask reduce, const ExecutorBasePtr &parent = ExecutorBasePtr()); + SyncReduceExecutor(SyncReduceTask reduce, ErrorHandler errorHandler, const ExecutorBasePtr &parent); }; template class SyncEachExecutor : public Executor { public: - SyncEachExecutor(SyncEachTask each, const ExecutorBasePtr &parent = ExecutorBasePtr()); + SyncEachExecutor(SyncEachTask each, ErrorHandler errorHandler, const ExecutorBasePtr &parent); void previousFutureReady(); protected: SyncEachTask mFunc; @@ -190,12 +190,14 @@ Job start(ThenTask func); template Job null() { - return Async::start([](Async::Future &future) {future.setFinished();}); + return Async::start([](Async::Future &future) { + future.setFinished(); + }); } /** * An error job. - * + * * An async error. * */ @@ -288,35 +290,35 @@ public: } template - Job each(EachTask func) + Job each(EachTask func, ErrorHandler errorFunc = ErrorHandler()) { eachInvariants(); return Job(Private::ExecutorBasePtr( - new Private::EachExecutor(func, mExecutor))); + new Private::EachExecutor(func, errorFunc, mExecutor))); } template - Job each(SyncEachTask func) + Job each(SyncEachTask func, ErrorHandler errorFunc = ErrorHandler()) { eachInvariants(); return Job(Private::ExecutorBasePtr( - new Private::SyncEachExecutor(func, mExecutor))); + new Private::SyncEachExecutor(func, errorFunc, mExecutor))); } template - Job reduce(ReduceTask func) + Job reduce(ReduceTask func, ErrorHandler errorFunc = ErrorHandler()) { reduceInvariants(); return Job(Private::ExecutorBasePtr( - new Private::ReduceExecutor(func, mExecutor))); + new Private::ReduceExecutor(func, errorFunc, mExecutor))); } template - Job reduce(SyncReduceTask func) + Job reduce(SyncReduceTask func, ErrorHandler errorFunc = ErrorHandler()) { reduceInvariants(); return Job(Private::ExecutorBasePtr( - new Private::SyncReduceExecutor(func, mExecutor))); + new Private::SyncReduceExecutor(func, errorFunc, mExecutor))); } Async::Future exec() @@ -364,13 +366,13 @@ namespace Async { template Job start(ThenTask func) { - return Job(Private::ExecutorBasePtr(new Private::ThenExecutor(func))); + return Job(Private::ExecutorBasePtr(new Private::ThenExecutor(func, ErrorHandler(), Private::ExecutorBasePtr()))); } template Job start(SyncThenTask func) { - return Job(Private::ExecutorBasePtr(new Private::SyncThenExecutor(func))); + return Job(Private::ExecutorBasePtr(new Private::SyncThenExecutor(func, ErrorHandler(), Private::ExecutorBasePtr()))); } namespace Private { @@ -390,27 +392,47 @@ template void Executor::exec() { mPrevFuture = chainup(); + // Initialize our future mResult = new Async::Future(); if (!mPrevFuture || mPrevFuture->isFinished()) { + if (mPrevFuture && mPrevFuture->errorCode() != 0) { + if (mErrorFunc) { + mErrorFunc(mPrevFuture->errorCode(), mPrevFuture->errorMessage()); + mResult->setFinished(); + return; + } else { + // Propagate the error to next caller + } + } previousFutureReady(); } else { auto futureWatcher = new Async::FutureWatcher(); QObject::connect(futureWatcher, &Async::FutureWatcher::futureReady, [futureWatcher, this]() { - assert(futureWatcher->future().isFinished()); + auto prevFuture = futureWatcher->future(); + assert(prevFuture.isFinished()); futureWatcher->deleteLater(); + if (prevFuture.errorCode() != 0) { + if (mErrorFunc) { + mErrorFunc(prevFuture.errorCode(), prevFuture.errorMessage()); + mResult->setFinished(); + return; + } else { + // Propagate the error to next caller + } + } previousFutureReady(); }); + futureWatcher->setFuture(*mPrevFuture); } } template ThenExecutor::ThenExecutor(ThenTask then, ErrorHandler error, const ExecutorBasePtr &parent) - : Executor::type, Out, In ...>(parent) + : Executor::type, Out, In ...>(error, parent) { this->mFunc = then; - this->mErrorFunc = error; } template @@ -419,25 +441,14 @@ void ThenExecutor::previousFutureReady() if (this->mPrevFuture) { assert(this->mPrevFuture->isFinished()); } - if (this->mPrevFuture && this->mPrevFuture->errorCode()) { - if (this->mErrorFunc) { - this->mErrorFunc(this->mPrevFuture->errorCode(), this->mPrevFuture->errorMessage()); - this->mResult->setFinished(); - } else { - static_cast*>(this->mResult)->setError(this->mPrevFuture->errorCode(), this->mPrevFuture->errorMessage()); - //propagate error if no error handler is available - this->mFunc(this->mPrevFuture ? this->mPrevFuture->value() : In() ..., - *static_cast*>(this->mResult)); - } - } else { - this->mFunc(this->mPrevFuture ? this->mPrevFuture->value() : In() ..., - *static_cast*>(this->mResult)); - } + + this->mFunc(this->mPrevFuture ? this->mPrevFuture->value() : In() ..., + *static_cast*>(this->mResult)); } template -EachExecutor::EachExecutor(EachTask each, const ExecutorBasePtr &parent) - : Executor(parent) +EachExecutor::EachExecutor(EachTask each, ErrorHandler error, const ExecutorBasePtr &parent) + : Executor(error, parent) { this->mFunc = each; } @@ -474,17 +485,16 @@ void EachExecutor::previousFutureReady() } template -ReduceExecutor::ReduceExecutor(ReduceTask reduce, const ExecutorBasePtr &parent) - : ThenExecutor(reduce, ErrorHandler(), parent) +ReduceExecutor::ReduceExecutor(ReduceTask reduce, ErrorHandler error, const ExecutorBasePtr &parent) + : ThenExecutor(reduce, error, parent) { } template SyncThenExecutor::SyncThenExecutor(SyncThenTask then, ErrorHandler errorHandler, const ExecutorBasePtr &parent) - : Executor::type, Out, In ...>(parent) + : Executor::type, Out, In ...>(errorHandler, parent) { this->mFunc = then; - this->mErrorFunc = errorHandler; } template @@ -494,27 +504,14 @@ void SyncThenExecutor::previousFutureReady() assert(this->mPrevFuture->isFinished()); } - if (this->mPrevFuture && this->mPrevFuture->errorCode()) { - if (this->mErrorFunc) { - this->mErrorFunc(this->mPrevFuture->errorCode(), this->mPrevFuture->errorMessage()); - this->mResult->setFinished(); - } else { - static_cast*>(this->mResult)->setError(this->mPrevFuture->errorCode(), this->mPrevFuture->errorMessage()); - //propagate error if no error handler is available - Out result = this->mFunc(this->mPrevFuture ? this->mPrevFuture->value() : In() ...); - static_cast*>(this->mResult)->setValue(result); - this->mResult->setFinished(); - } - } else { - Out result = this->mFunc(this->mPrevFuture ? this->mPrevFuture->value() : In() ...); - static_cast*>(this->mResult)->setValue(result); - this->mResult->setFinished(); - } + Out result = this->mFunc(this->mPrevFuture ? this->mPrevFuture->value() : In() ...); + static_cast*>(this->mResult)->setValue(result); + this->mResult->setFinished(); } template -SyncEachExecutor::SyncEachExecutor(SyncEachTask each, const ExecutorBasePtr &parent) - : Executor(parent) +SyncEachExecutor::SyncEachExecutor(SyncEachTask each, ErrorHandler errorHandler, const ExecutorBasePtr &parent) + : Executor(errorHandler, parent) { this->mFunc = each; } @@ -536,8 +533,8 @@ void SyncEachExecutor::previousFutureReady() } template -SyncReduceExecutor::SyncReduceExecutor(SyncReduceTask reduce, const ExecutorBasePtr &parent) - : SyncThenExecutor(reduce, ErrorHandler(), parent) +SyncReduceExecutor::SyncReduceExecutor(SyncReduceTask reduce, ErrorHandler errorHandler, const ExecutorBasePtr &parent) + : SyncThenExecutor(reduce, errorHandler, parent) { } -- cgit v1.2.3