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 |