/// <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); }