Mercurial > pub > ImplabNet
comparison Implab/ActionChainTaskBase.cs @ 187:dd4a3590f9c6 ref20160224
Reworked cancelation handling, if the cancel handler isn't specified the OperationCanceledException will be handled by the error handler
Any unhandled OperationCanceledException will cause the promise cancelation
| author | cin | 
|---|---|
| date | Tue, 19 Apr 2016 17:35:20 +0300 | 
| parents | 75103928da09 | 
| children | 40d7fed4a09e | 
   comparison
  equal
  deleted
  inserted
  replaced
| 186:75103928da09 | 187:dd4a3590f9c6 | 
|---|---|
| 1 using System; | 1 using System; | 
| 2 using System.Threading; | 2 using System.Threading; | 
| 3 | 3 | 
| 4 namespace Implab { | 4 namespace Implab { | 
| 5 public class ActionChainTaskBase : AbstractPromise { | 5 public class ActionChainTaskBase : AbstractTask { | 
| 6 readonly Func<Exception, IPromise> m_error; | 6 readonly Func<Exception, IPromise> m_error; | 
| 7 readonly Func<Exception, IPromise> m_cancel; | 7 readonly Func<Exception, IPromise> m_cancel; | 
| 8 | |
| 9 int m_cancelationLock; | |
| 10 | 8 | 
| 11 protected ActionChainTaskBase(Func<Exception, IPromise> error, Func<Exception, IPromise> cancel, bool autoCancellable) { | 9 protected ActionChainTaskBase(Func<Exception, IPromise> error, Func<Exception, IPromise> cancel, bool autoCancellable) { | 
| 12 m_error = error; | 10 m_error = error; | 
| 13 m_cancel = cancel; | 11 m_cancel = cancel; | 
| 14 if (autoCancellable) | 12 if (autoCancellable) | 
| 19 if (LockCancelation()) | 17 if (LockCancelation()) | 
| 20 HandleErrorInternal(error); | 18 HandleErrorInternal(error); | 
| 21 } | 19 } | 
| 22 | 20 | 
| 23 public override void CancelOperation(Exception reason) { | 21 public override void CancelOperation(Exception reason) { | 
| 24 if (LockCancelation()) { | 22 if (LockCancelation()) | 
| 25 if (!(reason is OperationCanceledException)) | 23 // отмена вызвана до начала выполнения задачи | 
| 26 reason = reason != null ? new OperationCanceledException(null, reason) : new OperationCanceledException(); | 24 HandleCancelInternal(reason); | 
| 27 | 25 } | 
| 28 if (m_cancel != null) { | 26 | 
| 29 try { | 27 protected void HandleCancelInternal(Exception reason) { | 
| 30 m_cancel(reason).On(SetResult, HandleErrorInternal, HandleCancelInternal); | 28 if (m_cancel != null) { | 
| 31 } catch (Exception err) { | 29 try { | 
| 32 HandleErrorInternal(err); | 30 // вызываем обработчик отмены | 
| 33 } | 31 var p = m_cancel(reason); | 
| 34 } else { | 32 p.On(SetResult, HandleErrorInternal, SetCancelledInternal); | 
| 35 HandleErrorInternal(reason); | 33 // сообщаем асинхронной операции, что клиент уже не хочет получать результат | 
| 34 // т.е. если он инициировал отмену, задача отменилась, вызвался обрабочик отмены | |
| 35 // отбработчику сообщили, что результат уже не нужен и уже сам обработчик решает | |
| 36 // отдавать ли результат или подтвердить отмену (или вернуть ошибку). | |
| 37 CancellationRequested(p.Cancel); | |
| 38 } catch (Exception err) { | |
| 39 HandleErrorInternal(err); | |
| 36 } | 40 } | 
| 41 } else { | |
| 42 HandleErrorInternal(reason ?? new OperationCanceledException()); | |
| 37 } | 43 } | 
| 38 } | 44 } | 
| 39 | 45 | 
| 40 void HandleCancelInternal(Exception reason) { | 46 protected void HandleErrorInternal(Exception error) { | 
| 41 if (!(reason is OperationCanceledException)) | |
| 42 reason = reason != null ? new OperationCanceledException(null, reason) : new OperationCanceledException(); | |
| 43 HandleErrorInternal(reason); | |
| 44 } | |
| 45 | |
| 46 void HandleErrorInternal(Exception error) { | |
| 47 if (m_error != null) { | 47 if (m_error != null) { | 
| 48 try { | 48 try { | 
| 49 var p = m_error(error); | 49 var p = m_error(error); | 
| 50 p.On(SetResult, SetError, SetCancelled); | 50 p.On(SetResult, SetErrorInternal, SetCancelledInternal); | 
| 51 CancellationRequested(p.Cancel); | 51 CancellationRequested(p.Cancel); | 
| 52 } catch (Exception err) { | 52 } catch (Exception err) { | 
| 53 error = err; | 53 SetErrorInternal(error); | 
| 54 } | 54 } | 
| 55 } else { | 55 } else { | 
| 56 SetErrorInternal(error); | 56 SetErrorInternal(error); | 
| 57 } | 57 } | 
| 58 } | 58 } | 
| 59 | 59 | 
| 60 void SetErrorInternal(Exception error) { | |
| 61 while (error is PromiseTransientException) | |
| 62 error = error.InnerException; | |
| 63 | |
| 64 if (error is OperationCanceledException) | |
| 65 SetCancelled(error); | |
| 66 else | |
| 67 SetError(error); | |
| 68 } | |
| 69 | |
| 70 protected bool LockCancelation() { | |
| 71 return 0 == Interlocked.CompareExchange(ref m_cancelationLock, 1, 0); | |
| 72 } | |
| 73 } | 60 } | 
| 74 } | 61 } | 
| 75 | 62 | 
