11using System ;
2+ using System . Threading ;
23using System . Threading . Tasks ;
34using System . Threading . Tasks . Dataflow ;
45
56namespace Dbosoft . Functional
67{
78 public static class Agent
89 {
9- public static IAgent < TMsg > Start < TMsg > ( Action < TMsg > action )
10- => new StatelessAgent < TMsg > ( action ) ;
10+ public static IAgent < TMsg > Start < TMsg > ( Action < TMsg > action , CancellationToken cancellationToken = default )
11+ => new StatelessAgent < TMsg > ( action , cancellationToken ) ;
1112
1213 public static IAgent < TMsg > Start < TState , TMsg >
1314 ( Func < TState > initState
14- , Func < TState , TMsg , TState > process )
15- => new StatefulAgent < TState , TMsg > ( initState ( ) , process ) ;
15+ , Func < TState , TMsg , TState > process , CancellationToken cancellationToken = default )
16+ => new StatefulAgent < TState , TMsg > ( initState ( ) , process , cancellationToken ) ;
1617
1718 public static IAgent < TMsg > Start < TState , TMsg >
1819 ( TState initialState
19- , Func < TState , TMsg , TState > process )
20- => new StatefulAgent < TState , TMsg > ( initialState , process ) ;
20+ , Func < TState , TMsg , TState > process , CancellationToken cancellationToken = default )
21+ => new StatefulAgent < TState , TMsg > ( initialState , process , cancellationToken ) ;
2122
2223 public static IAgent < TMsg > Start < TState , TMsg >
2324 ( TState initialState
24- , Func < TState , TMsg , Task < TState > > process )
25- => new StatefulAgent < TState , TMsg > ( initialState , process ) ;
25+ , Func < TState , TMsg , Task < TState > > process , CancellationToken cancellationToken = default )
26+ => new StatefulAgent < TState , TMsg > ( initialState , process , cancellationToken ) ;
2627
2728 public static IAgent < TMsg , TReply > Start < TState , TMsg , TReply >
2829 ( TState initialState
29- , Func < TState , TMsg , ( TState , TReply ) > process )
30- => new TwoWayAgent < TState , TMsg , TReply > ( initialState , process ) ;
30+ , Func < TState , TMsg , ( TState , TReply ) > process , CancellationToken cancellationToken = default )
31+ => new TwoWayAgent < TState , TMsg , TReply > ( initialState , process , cancellationToken ) ;
3132
3233 public static IAgent < TMsg , TReply > Start < TState , TMsg , TReply >
3334 ( TState initialState
34- , Func < TState , TMsg , Task < ( TState , TReply ) > > process )
35- => new TwoWayAgent < TState , TMsg , TReply > ( initialState , process ) ;
35+ , Func < TState , TMsg , Task < ( TState , TReply ) > > process , CancellationToken cancellationToken = default )
36+ => new TwoWayAgent < TState , TMsg , TReply > ( initialState , process , cancellationToken ) ;
3637 }
3738
3839 public interface IAgent < in TMsg >
@@ -49,14 +50,15 @@ class StatelessAgent<TMsg> : IAgent<TMsg>
4950 {
5051 private readonly ActionBlock < TMsg > _actionBlock ;
5152
52- public StatelessAgent ( Action < TMsg > process )
53+ public StatelessAgent ( Action < TMsg > process , CancellationToken cancellationToken )
5354 {
54- _actionBlock = new ActionBlock < TMsg > ( process ) ;
55+ _actionBlock = new ActionBlock < TMsg > ( process , new ExecutionDataflowBlockOptions { CancellationToken = cancellationToken } ) ;
5556 }
5657
57- public StatelessAgent ( Func < TMsg , Task > process )
58+ public StatelessAgent ( Func < TMsg , Task > process , CancellationToken cancellationToken )
5859 {
59- _actionBlock = new ActionBlock < TMsg > ( process ) ;
60+ _actionBlock = new ActionBlock < TMsg > ( process , new ExecutionDataflowBlockOptions { CancellationToken = cancellationToken } ) ;
61+
6062 }
6163
6264 public void Tell ( TMsg message ) => _actionBlock . Post ( message ) ;
@@ -68,32 +70,36 @@ class StatefulAgent<TState, TMsg> : IAgent<TMsg>
6870 private readonly ActionBlock < TMsg > _actionBlock ;
6971
7072 public StatefulAgent ( TState initialState
71- , Func < TState , TMsg , TState > process )
73+ , Func < TState , TMsg , TState > process , CancellationToken cancellationToken )
7274 {
7375 _state = initialState ;
7476
7577 _actionBlock = new ActionBlock < TMsg > (
76- msg => _state = process ( _state , msg ) ) ; // process the message with the current state, and store the resulting new state as the current state of the agent
78+ msg => _state = process ( _state , msg ) , // process the message with the current state, and store the resulting new state as the current state of the agent
79+ new ExecutionDataflowBlockOptions { CancellationToken = cancellationToken } ) ;
7780 }
7881
7982 public StatefulAgent ( TState initialState
80- , Func < TState , TMsg , Task < TState > > process )
83+ , Func < TState , TMsg , Task < TState > > process , CancellationToken cancellationToken )
8184 {
8285 _state = initialState ;
8386
8487 _actionBlock = new ActionBlock < TMsg > (
85- async msg => _state = await process ( _state , msg ) ) ;
88+ async msg => _state = await process ( _state , msg ) ,
89+ new ExecutionDataflowBlockOptions { CancellationToken = cancellationToken } ) ;
8690 }
8791
8892 public void Tell ( TMsg message ) => _actionBlock . Post ( message ) ;
8993 }
9094
9195 class TwoWayAgent < TState , TMsg , TReply > : IAgent < TMsg , TReply >
9296 {
97+ private readonly CancellationToken _cancellationToken ;
9398 private readonly ActionBlock < ( TMsg , TaskCompletionSource < TReply > ) > _actionBlock ;
9499
95- public TwoWayAgent ( TState initialState , Func < TState , TMsg , ( TState , TReply ) > process )
100+ public TwoWayAgent ( TState initialState , Func < TState , TMsg , ( TState , TReply ) > process , CancellationToken cancellationToken )
96101 {
102+ _cancellationToken = cancellationToken ;
97103 var state = initialState ;
98104
99105 _actionBlock = new ActionBlock < ( TMsg , TaskCompletionSource < TReply > ) > (
@@ -102,17 +108,19 @@ public TwoWayAgent(TState initialState, Func<TState, TMsg, (TState, TReply)> pro
102108 var result = process ( state , t . Item1 ) ;
103109 state = result . Item1 ;
104110 t . Item2 . SetResult ( result . Item2 ) ;
105- } ) ;
111+ } , new ExecutionDataflowBlockOptions { CancellationToken = cancellationToken } ) ;
106112 }
107113
108114 // creates a 2-way agent with an async processing func
109- public TwoWayAgent ( TState initialState , Func < TState , TMsg , Task < ( TState , TReply ) > > process )
115+ public TwoWayAgent ( TState initialState , Func < TState , TMsg , Task < ( TState , TReply ) > > process , CancellationToken cancellationToken )
110116 {
111117 var state = initialState ;
118+ _cancellationToken = cancellationToken ;
112119
113120 _actionBlock = new ActionBlock < ( TMsg , TaskCompletionSource < TReply > ) > (
114121 async t =>
115122 {
123+
116124 await process ( state , t . Item1 )
117125 . ContinueWith ( task =>
118126 {
@@ -125,16 +133,16 @@ await process(state, t.Item1)
125133 }
126134 } )
127135 . ConfigureAwait ( false ) ;
128- } ) ;
136+ } , new ExecutionDataflowBlockOptions { CancellationToken = cancellationToken } ) ;
129137 }
130138
131139 public Task < TReply > Tell ( TMsg message )
132140 {
133141 var tcs = new TaskCompletionSource < TReply > ( ) ;
134142 _actionBlock . Post ( ( message , tcs ) ) ;
135-
143+
136144 // this will help to relax the task scheduler, for some reason the task may block if directly returned
137- tcs . Task . Wait ( 10000 ) ;
145+ tcs . Task . Wait ( _cancellationToken ) ;
138146 return tcs . Task ;
139147 }
140148 }
0 commit comments