示例#1
0
        private static async Task <object> Ask(ICanTell self, Func <IActorRef, object> messageFactory, IActorRefProvider provider,
                                               TimeSpan?timeout, CancellationToken cancellationToken)
        {
            TaskCompletionSource <object> result = TaskEx.NonBlockingTaskCompletionSource <object>();

            CancellationTokenSource timeoutCancellation = null;

            timeout = timeout ?? provider.Settings.AskTimeout;
            var ctrList = new List <CancellationTokenRegistration>(2);

            if (timeout != Timeout.InfiniteTimeSpan && timeout.Value > default(TimeSpan))
            {
                timeoutCancellation = new CancellationTokenSource();

                ctrList.Add(timeoutCancellation.Token.Register(() =>
                {
                    result.TrySetException(new AskTimeoutException($"Timeout after {timeout} seconds"));
                }));

                timeoutCancellation.CancelAfter(timeout.Value);
            }

            if (cancellationToken.CanBeCanceled)
            {
                ctrList.Add(cancellationToken.Register(() => result.TrySetCanceled()));
            }

            //create a new tempcontainer path
            ActorPath path = provider.TempPath();

            var future = new FutureActorRef(result, () => { }, path);

            //The future actor needs to be registered in the temp container
            provider.RegisterTempActor(future, path);
            var message = messageFactory(future);

            self.Tell(message, future);

            try
            {
                return(await result.Task);
            }
            finally
            {
                //callback to unregister from tempcontainer

                provider.UnregisterTempActor(path);

                for (var i = 0; i < ctrList.Count; i++)
                {
                    ctrList[i].Dispose();
                }

                if (timeoutCancellation != null)
                {
                    timeoutCancellation.Dispose();
                }
            }
        }
示例#2
0
        /// <summary>
        /// TBD
        /// </summary>
        /// <typeparam name="T">TBD</typeparam>
        /// <param name="self">TBD</param>
        /// <param name="messageFactory">Factory method that creates a message that can encapsulate the 'Sender' IActorRef</param>
        /// <param name="timeout">TBD</param>
        /// <param name="cancellationToken">TBD</param>
        /// <exception cref="ArgumentException">
        /// This exception is thrown if the system can't resolve the target provider.
        /// </exception>
        /// <returns>TBD</returns>
        public static Task <T> Ask <T>(this ICanTell self, Func <IActorRef, object> messageFactory, TimeSpan?timeout, CancellationToken cancellationToken)
        {
            IActorRefProvider provider = ResolveProvider(self);

            if (provider == null)
            {
                throw new ArgumentException("Unable to resolve the target Provider", nameof(self));
            }

            var result = TaskEx.NonBlockingTaskCompletionSource <T>();

            CancellationTokenSource timeoutCancellation = null;

            timeout = timeout ?? provider.Settings.AskTimeout;

            CancellationTokenRegistration?ctr1 = null;
            CancellationTokenRegistration?ctr2 = null;

            if (timeout != Timeout.InfiniteTimeSpan && timeout.Value > default(TimeSpan))
            {
                timeoutCancellation = new CancellationTokenSource();

                ctr1 = timeoutCancellation.Token.Register(() =>
                {
                    result.TrySetException(new AskTimeoutException($"Timeout after {timeout} seconds"));
                });

                timeoutCancellation.CancelAfter(timeout.Value);
            }

            if (cancellationToken.CanBeCanceled)
            {
                ctr2 = cancellationToken.Register(() => result.TrySetCanceled());
            }

            var future = provider.CreateFutureRef(result);
            var path   = future.Path;

            //The future actor needs to be unregistered in the temp container
            _ = result.Task.ContinueWith(t =>
            {
                provider.UnregisterTempActor(path);

                ctr1?.Dispose();
                ctr2?.Dispose();
                timeoutCancellation?.Dispose();
            }, TaskContinuationOptions.ExecuteSynchronously);

            //The future actor needs to be registered in the temp container
            provider.RegisterTempActor(future, path);
            var message = messageFactory(future);

            self.Tell(message, future);

            return(result.Task);
        }