/// <summary>
        ///     Unregisters an observable. This method is invoked by an observable.
        /// </summary>
        /// <param name="topic">The topic.</param>
        /// <param name="entityId">The entity id of the observable.</param>
        /// <param name="observers">
        ///     A list of observers in the same cluster node. This field is optional.
        ///     When the list if not null or empty, the observer will forward the message to each observer which EntityId is in the
        ///     list.
        /// </param>
        /// <returns>The asynchronous result of the operation.</returns>
        public async Task UnregisterObservableAsync(string topic, EntityId entityId, IEnumerable <EntityId> observers)
        {
            EntityId id = await this.GetEntityIdAsync();

            if (id == null)
            {
                return;
            }
            if (string.IsNullOrWhiteSpace(topic))
            {
                throw new ArgumentException($"The {nameof(topic)} parameter cannot be null.", nameof(topic));
            }
            if (entityId == null)
            {
                throw new ArgumentException($"The {nameof(entityId)} parameter cannot be null.", nameof(entityId));
            }
            for (int k = 1; k <= ConfigurationHelper.MaxQueryRetryCount; k++)
            {
                try
                {
                    ConditionalValue <Dictionary <Uri, EntityId> > topicState = await this.StateManager.TryGetStateAsync <Dictionary <Uri, EntityId> >(topic);

                    if (!topicState.HasValue)
                    {
                        ActorEventSource.Current.Message(
                            $"Observer not registered to the specified topic.\r\n[Observable]: {entityId}\r\n[Observer]: {id}\r\n[Publication]: Topic=[{topic}]");
                        return;
                    }
                    Dictionary <Uri, EntityId> observableDictionary = topicState.Value;
                    if (!observableDictionary.ContainsKey(entityId.EntityUri))
                    {
                        ActorEventSource.Current.Message(
                            $"Observer not registered to the specified observable.\r\n[Observable]: {entityId}\r\n[Observer]: {id}\r\n[Publication]: Topic=[{topic}]");
                        return;
                    }
                    observableDictionary.Remove(entityId.EntityUri);
                    if (!observableDictionary.Any())
                    {
                        await this.StateManager.TryRemoveStateAsync(topic);
                    }
                    else
                    {
                        await this.StateManager.SetStateAsync(topic, observableDictionary);
                    }
                    ActorEventSource.Current.Message(
                        $"Observable successfully unregistered.\r\n[Observable]: {entityId}\r\n[Observer]: {id}\r\n[Publication]: Topic=[{topic}]");
                    break;
                }
                catch (FabricTransientException ex)
                {
                    ActorEventSource.Current.Error(ex);
                    if (k == ConfigurationHelper.MaxQueryRetryCount)
                    {
                        throw new TimeoutException(Constants.RetryTimeoutExhausted);
                    }
                }
                catch (AggregateException ex)
                {
                    foreach (Exception e in ex.InnerExceptions)
                    {
                        ActorEventSource.Current.Error(e);
                    }
                    throw;
                }
                catch (Exception ex)
                {
                    ActorEventSource.Current.Error(ex);
                    throw;
                }
                await Task.Delay(ConfigurationHelper.BackoffQueryDelay);
            }
            try
            {
                if (observers != null)
                {
                    IList <EntityId> observerList = observers as IList <EntityId> ?? observers.ToList();
                    if (observerList.Any())
                    {
                        StringBuilder builder = new StringBuilder($"Observer Proxy:\r\n[From]: {id}");
                        foreach (EntityId item in observerList)
                        {
                            builder.Append($"\r\n[To]: {item}");
                        }
                        ActorEventSource.Current.Message(builder.ToString());
                        List <Task> taskList = new List <Task>();
                        taskList.AddRange(observerList.Select(observer => ProcessingHelper.UnregisterObservableAsync(topic, observer, entityId, null)));
                        await Task.WhenAll(taskList.ToArray());
                    }
                }
            }
            catch (AggregateException ex)
            {
                foreach (Exception e in ex.InnerExceptions)
                {
                    ActorEventSource.Current.Error(e);
                }
                throw;
            }
            catch (Exception ex)
            {
                ActorEventSource.Current.Error(ex);
                throw;
            }
            if (this.ObservableUnregistered == null)
            {
                return;
            }
            try
            {
                Delegate[]            invocationList = this.ObservableUnregistered.GetInvocationList();
                Task[]                handlerTasks   = new Task[invocationList.Length];
                SubscriptionEventArgs args           = new SubscriptionEventArgs(topic, entityId);
                for (int i = 0; i < invocationList.Length; i++)
                {
                    handlerTasks[i] = ProcessingHelper.ExecuteEventHandlerAsync((Func <SubscriptionEventArgs, Task>)invocationList[i], args);
                }
                await Task.WhenAll(handlerTasks);
            }
            catch (AggregateException ex)
            {
                foreach (Exception e in ex.InnerExceptions)
                {
                    ActorEventSource.Current.Error(e);
                }
            }
            catch (Exception ex)
            {
                ActorEventSource.Current.Error(ex);
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Unregisters an entity as observable for a given topic.
        /// This method is called by a management service or actor.
        /// </summary>
        /// <param name="topic">The topic.</param>
        /// <param name="useObserverAsProxy">Observable uses one observer for each cluster node as a proxy when true,
        /// it directly sends the message to all observers otherwise.</param>
        /// <returns>The asynchronous result of the operation.</returns>
        public async Task UnregisterObservableActorAsync(string topic, bool useObserverAsProxy)
        {
            EntityId id = await this.GetEntityIdAsync();

            if (id == null)
            {
                return;
            }
            if (string.IsNullOrWhiteSpace(topic))
            {
                throw new ArgumentException($"The {nameof(topic)} parameter cannot be null.", nameof(topic));
            }
            ConditionalValue <Dictionary <Uri, ObserverInfo> > topicState = await this.StateManager.TryGetStateAsync <Dictionary <Uri, ObserverInfo> >(topic);

            if (!topicState.HasValue)
            {
                throw new ArgumentException($"{id} is not an observable for Topic=[{topic}]");
            }
            Dictionary <Uri, ObserverInfo> observerDictionary = topicState.Value;

            try
            {
                for (int k = 1; k <= ConfigurationHelper.MaxQueryRetryCount; k++)
                {
                    try
                    {
                        IRegistryService registryService = ServiceProxy.Create <IRegistryService>(ConfigurationHelper.RegistryServiceUri,
                                                                                                  new ServicePartitionKey(PartitionResolver.Resolve(topic, ConfigurationHelper.RegistryServicePartitionCount)));
                        await registryService.UnregisterObservableAsync(topic, id);

                        break;
                    }
                    catch (FabricTransientException ex)
                    {
                        ActorEventSource.Current.Error(ex);
                        if (k == ConfigurationHelper.MaxQueryRetryCount)
                        {
                            throw;
                        }
                    }
                    catch (AggregateException ex)
                    {
                        foreach (Exception innerException in ex.InnerExceptions)
                        {
                            ActorEventSource.Current.Error(innerException);
                        }
                        if (k == ConfigurationHelper.MaxQueryRetryCount)
                        {
                            throw;
                        }
                    }
                    catch (Exception ex)
                    {
                        ActorEventSource.Current.Error(ex);
                        if (k == ConfigurationHelper.MaxQueryRetryCount)
                        {
                            throw;
                        }
                    }
                    await Task.Delay(ConfigurationHelper.BackoffQueryDelay);
                }
                List <Task> taskList = new List <Task>();

                try
                {
                    if (useObserverAsProxy)
                    {
                        // observers are grouped by NodeName
                        taskList.AddRange(
                            observerDictionary.
                            Select(kvp => kvp.Value.EntityId).
                            GroupBy(e => e.NodeName).
                            Select(groupingByNodeName => ProcessingHelper.GetObserverProxyAndList(groupingByNodeName, true)).
                            Select(tuple => ProcessingHelper.UnregisterObservableAsync(topic, tuple.Item1, id, tuple.Item2)));
                    }
                    else
                    {
                        taskList.AddRange(
                            observerDictionary.Select(
                                observer => ProcessingHelper.UnregisterObservableAsync(topic, observer.Value.EntityId, id, null)));
                    }
                    await Task.WhenAll(taskList.ToArray());
                }
                catch (AggregateException ex)
                {
                    foreach (Exception e in ex.InnerExceptions)
                    {
                        ActorEventSource.Current.Error(e);
                    }
                }
                catch (Exception ex)
                {
                    ActorEventSource.Current.Error(ex);
                }
                await this.StateManager.TryRemoveStateAsync(topic);

                ActorEventSource.Current.Message($"Observable successfully unregistered.\r\n[Observable]: {id}\r\n[Publication]: Topic=[{topic}].");
            }
            catch (FabricTransientException ex)
            {
                ActorEventSource.Current.Error(ex);
            }
            catch (AggregateException ex)
            {
                foreach (Exception e in ex.InnerExceptions)
                {
                    ActorEventSource.Current.Error(e);
                }
                throw;
            }
            catch (Exception ex)
            {
                ActorEventSource.Current.Error(ex);
                throw;
            }
        }