/// <summary>
        /// Reads the messages for the observer actor from its messagebox.
        /// </summary>
        /// <returns>The messages for the current observer actor.</returns>
        public virtual async Task <IEnumerable <Message> > ReadMessagesFromMessageBoxAsync()
        {
            EntityId id = await this.GetEntityIdAsync();

            IEnumerable <Message> messages = await ProcessingHelper.ReadMessagesFromMessageBoxAsync(id.EntityUri);

            if (messages == null)
            {
                return(null);
            }
            StringBuilder stringBuilder = new StringBuilder($"Messages read from the MessageBox.\r\n[Observer]: {id}");
            int           i             = 1;

            foreach (Message message in messages)
            {
                stringBuilder.Append($"\r\nMessage[{i++}]=[{message.Body}]");
            }
            ServiceEventSource.Current.Message(stringBuilder.ToString());
            return(messages);
        }
        /// <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);
            }
        }
        /// <summary>
        ///     Provides the observer with new data. This method is invoked by an observable.
        /// </summary>
        /// <param name="topic">The topic.</param>
        /// <param name="message">The current notification information.</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 virtual async Task NotifyObserverAsync(string topic, Message message, EntityId entityId, IEnumerable <EntityId> observers)
        {
            try
            {
                EntityId id = await this.GetEntityIdAsync();

                if (id == null)
                {
                    return;
                }
                if (entityId == null)
                {
                    entityId = new EntityId {
                        ActorId = ActorId.CreateRandom(), ServiceUri = this.ServiceUri
                    }
                }
                ;
                ActorEventSource.Current.Message(
                    $"Message Received.\r\n[Observable]: {entityId}\r\n[Observer]: {id}\r\n[Message]: Topic=[{topic}] Body=[{message?.Body ?? "NULL"}]");
                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.NotifyObserverAsync(
                                    topic,
                                    message,
                                    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.NotificationMessageReceived == null)
            {
                return;
            }
            try
            {
                Delegate[] invocationList            = this.NotificationMessageReceived.GetInvocationList();
                Task[]     handlerTasks              = new Task[invocationList.Length];
                NotificationEventArgs <Message> args = new NotificationEventArgs <Message>(topic, message, entityId);
                for (int i = 0; i < invocationList.Length; i++)
                {
                    handlerTasks[i] = ProcessingHelper.ExecuteEventHandlerAsync((Func <NotificationEventArgs <Message>, 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);
            }
        }
        /// <summary>
        /// Provides the observer with new data. This method is invoked by an observable.
        /// </summary>
        /// <param name="topic">The topic.</param>
        /// <param name="message">The current notification information.</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 NotifyObserverAsync(string topic, Message message, EntityId entityId, IEnumerable <EntityId> observers)
        {
            EntityId id = null;

            for (int k = 1; k <= ConfigurationHelper.MaxQueryRetryCount; k++)
            {
                try
                {
                    id = await this.GetEntityIdAsync();

                    break;
                }
                catch (FabricTransientException ex)
                {
                    ServiceEventSource.Current.Error(ex);
                    if (k == ConfigurationHelper.MaxQueryRetryCount)
                    {
                        throw new TimeoutException(Constants.RetryTimeoutExhausted);
                    }
                }
                catch (AggregateException ex)
                {
                    foreach (Exception e in ex.InnerExceptions)
                    {
                        ServiceEventSource.Current.Error(e);
                    }
                    throw;
                }
                catch (Exception ex)
                {
                    ServiceEventSource.Current.Error(ex);
                    throw;
                }
                await Task.Delay(ConfigurationHelper.BackoffQueryDelay);
            }
            try
            {
                ServiceEventSource.Current.Message(
                    $"Message Received.\r\n[Observable]: {entityId}\r\n[Observer]: {id}\r\n[Message]: Topic=[{topic}] Body=[{message?.Body ?? "NULL"}]");
                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}");
                        }
                        ServiceEventSource.Current.Message(builder.ToString());
                        List <Task> taskList = new List <Task>();
                        taskList.AddRange(
                            observerList.Select(
                                observer => ProcessingHelper.NotifyObserverAsync(
                                    topic,
                                    message,
                                    observer,
                                    entityId,
                                    null)));
                        await Task.WhenAll(taskList.ToArray());
                    }
                }
            }
            catch (AggregateException ex)
            {
                foreach (Exception e in ex.InnerExceptions)
                {
                    ServiceEventSource.Current.Error(e);
                }
                throw;
            }
            catch (Exception ex)
            {
                ServiceEventSource.Current.Error(ex);
                throw;
            }
            if (this.NotificationMessageReceived == null)
            {
                return;
            }
            try
            {
                Delegate[] invocationList            = this.NotificationMessageReceived.GetInvocationList();
                Task[]     handlerTasks              = new Task[invocationList.Length];
                NotificationEventArgs <Message> args = new NotificationEventArgs <Message>(topic, message, entityId);
                for (int i = 0; i < invocationList.Length; i++)
                {
                    handlerTasks[i] = ProcessingHelper.ExecuteEventHandlerAsync((Func <NotificationEventArgs <Message>, Task>)invocationList[i], args);
                }
                await Task.WhenAll(handlerTasks);
            }
            catch (AggregateException ex)
            {
                foreach (Exception e in ex.InnerExceptions)
                {
                    ServiceEventSource.Current.Error(e);
                }
            }
            catch (Exception ex)
            {
                ServiceEventSource.Current.Error(ex);
            }
        }
Example #5
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;
            }
        }
Example #6
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;
            }
        }
Example #7
0
        /// <summary>
        /// Unregisters an observer. This methods is invoked by an observer.
        /// </summary>
        /// <param name="topic">The topic.</param>
        /// <param name="entityId">The entity id of the observer.</param>
        /// <returns>The asynchronous result of the operation.</returns>
        public async Task UnregisterObserverAsync(string topic, EntityId entityId)
        {
            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, ObserverInfo> > topicState = await this.StateManager.TryGetStateAsync <Dictionary <Uri, ObserverInfo> >(topic);

                    if (!topicState.HasValue)
                    {
                        return;
                    }
                    Dictionary <Uri, ObserverInfo> observerDictionary = topicState.Value;
                    if (!observerDictionary.ContainsKey(entityId.EntityUri))
                    {
                        return;
                    }
                    observerDictionary.Remove(entityId.EntityUri);
                    await this.StateManager.SetStateAsync(topic, observerDictionary);

                    ActorEventSource.Current.Message($"Observer successfully unregistered.\r\n[Observable]: {id}\r\n[Observer]: {entityId}\r\n[Subscription]: 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);
            }
            if (this.ObserverUnregistered == null)
            {
                return;
            }
            try
            {
                Delegate[]            invocationList = this.ObserverUnregistered.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);
            }
        }
Example #8
0
        /// <summary>
        /// Registers an observer. This methods is invoked by an observer.
        /// </summary>
        /// <param name="filterExpressions">Specifies filter expressions.</param>
        /// <param name="topic">The topic.</param>
        /// <param name="entityId">The entity id of the observer.</param>
        /// <returns>The asynchronous result of the operation.</returns>
        public async Task RegisterObserverAsync(string topic, IEnumerable <string> filterExpressions, EntityId entityId)
        {
            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 (entityId == null)
            {
                throw new ArgumentException($"The {nameof(entityId)} parameter cannot be null.", nameof(entityId));
            }
            IList <string> enumerable = filterExpressions as IList <string> ?? filterExpressions.ToList();

            for (int k = 1; k <= ConfigurationHelper.MaxQueryRetryCount; k++)
            {
                try
                {
                    if (!observerDictionary.ContainsKey(entityId.EntityUri))
                    {
                        observerDictionary.Add(entityId.EntityUri, new ObserverInfo(enumerable, entityId));
                        StringBuilder stringBuilder = new StringBuilder($"Observer successfully registered.\r\n[Observable]: {id}\r\n[Observer]: {entityId}\r\n[Subscription]: Topic=[{topic}]");
                        int           i             = 1;
                        foreach (string expression in enumerable.Where(expression => !string.IsNullOrWhiteSpace(expression)))
                        {
                            stringBuilder.Append($" FilterExpression[{i++}]=[{expression}]");
                        }
                        await this.StateManager.SetStateAsync(topic, observerDictionary);

                        ActorEventSource.Current.Message(stringBuilder.ToString());
                    }
                    else
                    {
                        StringBuilder stringBuilder = new StringBuilder($"Observer already registered.\r\n[Observable]: {id}\r\n[Observer]: {entityId}\r\n[Subscription]: Topic=[{topic}]");
                        int           i             = 1;
                        foreach (string expression in enumerable.Where(expression => !string.IsNullOrWhiteSpace(expression)))
                        {
                            stringBuilder.Append($" FilterExpression[{i++}]=[{expression}]");
                        }
                        ActorEventSource.Current.Message(stringBuilder.ToString());
                    }
                    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);
            }
            if (this.ObserverRegistered == null)
            {
                return;
            }
            try
            {
                Delegate[]            invocationList = this.ObserverRegistered.GetInvocationList();
                Task[]                handlerTasks   = new Task[invocationList.Length];
                SubscriptionEventArgs args           = new SubscriptionEventArgs(topic, enumerable, 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);
            }
        }
Example #9
0
        /// <summary>
        /// Unregisters an observer. This methods is invoked by an observer.
        /// </summary>
        /// <param name="topic">The topic.</param>
        /// <param name="entityId">The entity id of the observer.</param>
        /// <returns>The asynchronous result of the operation.</returns>
        public async Task UnregisterObserverAsync(string topic, EntityId entityId)
        {
            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
                {
                    EntityId id = await this.GetEntityIdAsync();

                    IReliableDictionary <string, Dictionary <Uri, ObserverInfo> > topicsDictionary =
                        await this.StateManager.GetOrAddAsync <IReliableDictionary <string, Dictionary <Uri, ObserverInfo> > >(Constants.TopicDictionary);

                    using (ITransaction transaction = this.StateManager.CreateTransaction())
                    {
                        ConditionalValue <Dictionary <Uri, ObserverInfo> > result = await topicsDictionary.TryGetValueAsync(transaction, topic);

                        if (!result.HasValue)
                        {
                            throw new ArgumentException($"{id} is not an observable for Topic=[{topic}]");
                        }
                        await transaction.CommitAsync();
                    }

                    using (ITransaction transaction = this.StateManager.CreateTransaction())
                    {
                        ConditionalValue <Dictionary <Uri, ObserverInfo> > result = await topicsDictionary.TryGetValueAsync(transaction, topic);

                        if (result.HasValue)
                        {
                            Dictionary <Uri, ObserverInfo> observers = result.Value;
                            if (observers.ContainsKey(entityId.EntityUri))
                            {
                                observers.Remove(entityId.EntityUri);
                                ServiceEventSource.Current.Message(
                                    $"Observer successfully unregistered.\r\n[Observable]: {id}\r\n[Observer]: {entityId}\r\n[Subscription]: Topic=[{topic}]");
                                await topicsDictionary.AddOrUpdateAsync(transaction, topic, e => observers, (e, s) => observers);
                            }
                        }
                        await transaction.CommitAsync();
                    }
                    break;
                }
                catch (FabricTransientException ex)
                {
                    ServiceEventSource.Current.Error(ex);
                    if (k == ConfigurationHelper.MaxQueryRetryCount)
                    {
                        throw;
                    }
                }
                catch (AggregateException ex)
                {
                    foreach (Exception e in ex.InnerExceptions)
                    {
                        ServiceEventSource.Current.Error(e);
                    }
                    throw;
                }
                catch (Exception ex)
                {
                    ServiceEventSource.Current.Error(ex);
                    throw;
                }
                await Task.Delay(ConfigurationHelper.BackoffQueryDelay);
            }
            if (this.ObserverUnregistered == null)
            {
                return;
            }
            try
            {
                Delegate[]            invocationList = this.ObserverUnregistered.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)
                {
                    ServiceEventSource.Current.Error(e);
                }
            }
            catch (Exception ex)
            {
                ServiceEventSource.Current.Error(ex);
            }
        }