Exemplo n.º 1
0
        /// <summary>
        /// Sends data to observers for a given topic.
        /// </summary>
        /// <param name="topic">The topic.</param>
        /// <param name="message">The current notification information.</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 NotifyObserversAsync(string topic, Message message, 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;

            if (string.IsNullOrWhiteSpace(message?.Body))
            {
                throw new ArgumentException($"The {nameof(message)} parameter cannot be null.", nameof(message));
            }
            try
            {
                List <Task> taskList = new List <Task>();
                if (useObserverAsProxy)
                {
                    if (JsonSerializerHelper.IsJson(message.Body))
                    {
                        // Create the list of observers: an observer is added to the list only at least of of its
                        // filter predicates is satisified by the message.
                        JObject jObject = JsonSerializerHelper.Deserialize(message.Body);
                        IEnumerable <EntityId> observerEnumerable = (from subscriptionInfo in observerDictionary.
                                                                     Where(kvp => kvp.Value.Predicates.Any()).
                                                                     Select(observer => observer.Value)
                                                                     let ok = subscriptionInfo.Predicates.Any(predicate => predicate(jObject))
                                                                              where ok
                                                                              select subscriptionInfo.EntityId);

                        // observers are grouped by NodeName
                        taskList.AddRange(
                            observerEnumerable.
                            GroupBy(e => e.NodeName).
                            Select(groupingByNodeName => ProcessingHelper.GetObserverProxyAndList(groupingByNodeName, true)).
                            Select(tuple => ProcessingHelper.NotifyObserverAsync(topic, message, tuple.Item1, id, tuple.Item2)));
                    }
                    else
                    {
                        // 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.NotifyObserverAsync(topic, message, tuple.Item1, id, tuple.Item2)));
                    }
                }
                else
                {
                    if (JsonSerializerHelper.IsJson(message.Body))
                    {
                        JObject jObject = JsonSerializerHelper.Deserialize(message.Body);
                        taskList.AddRange(
                            (from subscriptionInfo in observerDictionary.
                             Where(kvp => kvp.Value.Predicates.Any()).
                             Select(observer => observer.Value)
                             let ok = subscriptionInfo.Predicates.Any(predicate => predicate(jObject))
                                      where ok
                                      select subscriptionInfo.EntityId).
                            Select(
                                entityId => ProcessingHelper.NotifyObserverAsync(
                                    topic,
                                    message,
                                    entityId,
                                    id,
                                    null)));
                    }
                    else
                    {
                        taskList.AddRange(
                            observerDictionary.Select(
                                observer => ProcessingHelper.NotifyObserverAsync(
                                    topic,
                                    message,
                                    observer.Value.EntityId,
                                    id,
                                    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;
            }
        }
Exemplo 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;
            }
        }