Exemple #1
0
        private static void AgentExample()
        {
            //agents provide thread safety to individual functions.
            //in this case, we want one point for storing to the database that can be shared
            using var dataAccess = new AsyncAgent <object>(StoreToDatabase, x => { });

            object latestData = new object();

            //this could be called from multiple places, but all saves are sequential and thread safe
            dataAccess.Publish(latestData);

            Console.ReadKey();
        }
        public ReactiveAsyncAgent(
            TState initialState,
            Func <TState, TMessage, CancellationToken, Task <TState> > messageHandler,
            Func <Exception, CancellationToken, Task <bool> > errorHandler)
        {
            if (initialState == null)
            {
                throw new ArgumentNullException(nameof(initialState));
            }

            if (messageHandler == null)
            {
                throw new ArgumentNullException(nameof(messageHandler));
            }

            if (errorHandler == null)
            {
                throw new ArgumentNullException(nameof(errorHandler));
            }

            _stateSubject = new BehaviorSubject <TState>(initialState);
            _asyncAgent   = new AsyncAgent <TState, TMessage>(
                initialState: initialState,
                messageHandler: async(state, msg, ct) =>
            {
                TState newState = state;

                newState = await messageHandler(state, msg, ct);

                if (!ct.IsCancellationRequested)
                {
                    _stateSubject.OnNext(newState);
                }

                return(newState);
            },
                errorHandler: async(ex, ct) =>
            {
                bool shouldContinue = false;
                shouldContinue      = await errorHandler(ex, ct);

                if (!shouldContinue && !ct.IsCancellationRequested)
                {
                    _stateSubject.OnError(ex);
                }

                return(shouldContinue);
            });

            State = _stateSubject.AsObservable();
        }
Exemple #3
0
        public async Task AgentCanHandleMessage()
        {
            var tcs     = new TaskCompletionSource <string>();
            var message = "test";
            var agent   = new AsyncAgent <string, string>(
                string.Empty,
                async(state, msg, ct) =>
            {
                await Task.Delay(0, ct);
                tcs.SetResult(msg);
                return(state);
            },
                (ex, ct) => Task.FromResult(true));

            agent.Send(message);
            var processedMessage = await tcs.Task;

            Assert.Equal(message, processedMessage);
        }
Exemple #4
0
        public async Task AgentDoesNotHandleMessagesAfterDispose()
        {
            var tcs   = new TaskCompletionSource <int>();
            var agent = new AsyncAgent <int, int>(
                initialState: 0,
                messageHandler: async(state, msg, ct) =>
            {
                await Task.Delay(0, ct);
                tcs.SetResult(msg);
                return(state);
            },
                errorHandler: (ex, ct) => Task.FromResult(true));

            agent.Dispose();
            agent.Send(1);
            await Task.Delay(50);

            Assert.False(tcs.Task.IsCompleted);
        }
Exemple #5
0
        public async Task AgentHandlesMessagesInOrder()
        {
            var       parallelHandlers = 0;
            var       random           = new Random();
            Exception thrownException  = null;
            var       range            = Enumerable.Range(0, 10);
            var       tasks            = range.Select(_ => new TaskCompletionSource <int>()).ToList();
            var       agent            = new AsyncAgent <int, int>(
                initialState: 0,
                messageHandler: async(state, msg, ct) =>
            {
                if (1 != Interlocked.Increment(ref parallelHandlers))
                {
                    throw new Exception("parallelHandlers should be 1");
                }

                await Task.Delay(random.Next(5));

                if (0 != Interlocked.Decrement(ref parallelHandlers))
                {
                    throw new Exception("parrallelHandlers should be 0");
                }

                tasks[msg].SetResult(msg);

                return(state);
            },
                errorHandler: (ex, ct) =>
            {
                thrownException = ex;
                return(Task.FromResult(true));
            });

            foreach (var msg in range)
            {
                agent.Send(msg);
            }
            await Task.WhenAll(tasks.Select(item => item.Task).ToArray());

            Assert.Null(thrownException);
        }
Exemple #6
0
        public async Task AgentTriggersErrorHandler()
        {
            var tcs       = new TaskCompletionSource <Exception>();
            var message   = "test";
            var exception = new Exception();
            var agent     = new AsyncAgent <string, string>(
                initialState: string.Empty,
                messageHandler: async(state, msg, ct) =>
            {
                await Task.Delay(0, ct);
                throw exception;
            },
                errorHandler: (ex, ct) =>
            {
                tcs.SetResult(ex);
                return(Task.FromResult(true));
            });

            agent.Send(message);
            var triggeredException = await tcs.Task;

            Assert.Equal(exception, triggeredException);
        }