/// <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 observable.</param> /// This method is called by a management service or actor. /// <returns>The asynchronous result of the operation.</returns> public async Task UnregisterObserverActorAsync(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, 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; } if (entityId.Kind == EntityKind.Actor) { IServerObservableActor actorProxy = ActorProxy.Create <IServerObservableActor>(entityId.ActorId, entityId.ServiceUri); await actorProxy.UnregisterObserverAsync(topic, id); } else { IServerObservableService serviceProxy = entityId.PartitionKey.HasValue ? ServiceProxy.Create <IServerObservableService>(entityId.ServiceUri, new ServicePartitionKey(entityId.PartitionKey.Value)) : ServiceProxy.Create <IServerObservableService>(entityId.ServiceUri); await serviceProxy.UnregisterObserverAsync(topic, id); } observableDictionary.Remove(entityId.EntityUri); if (!observableDictionary.Any()) { await this.StateManager.TryRemoveStateAsync(topic); } else { await this.StateManager.SetStateAsync(topic, observableDictionary); } ActorEventSource.Current.Message( $"Observer successfully unregistered.\r\n[Observable]: {entityId}\r\n[Observer]: {id}\r\n[Subscription]: Topic=[{topic}]"); return; } 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; } await Task.Delay(ConfigurationHelper.BackoffQueryDelay); } throw new TimeoutException(Constants.RetryTimeoutExhausted); }
/// <summary> /// Registers an observer. This methods is invoked by an observer. /// </summary> /// <param name="topic">The topic.</param> /// <param name="filterExpressions">Specifies filter expressions.</param> /// <param name="entityId">The entity id of the observable.</param> /// This method is called by a management service or actor. /// <returns>The asynchronous result of the operation.</returns> public async Task RegisterObserverActorAsync(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)); } if (entityId == null) { throw new ArgumentException($"The {nameof(entityId)} parameter cannot be null.", nameof(entityId)); } IList <string> expressions = filterExpressions as IList <string> ?? filterExpressions.ToList(); for (int k = 1; k <= ConfigurationHelper.MaxQueryRetryCount; k++) { try { if (entityId.Kind == EntityKind.Actor) { IServerObservableActor actorProxy = ActorProxy.Create <IServerObservableActor>(entityId.ActorId, entityId.ServiceUri); await actorProxy.RegisterObserverAsync(topic, expressions, id); } else { IServerObservableService serviceProxy = entityId.PartitionKey.HasValue ? ServiceProxy.Create <IServerObservableService>(entityId.ServiceUri, new ServicePartitionKey(entityId.PartitionKey.Value)) : ServiceProxy.Create <IServerObservableService>(entityId.ServiceUri); await serviceProxy.RegisterObserverAsync(topic, expressions, id); } ConditionalValue <Dictionary <Uri, EntityId> > topicState = await this.StateManager.TryGetStateAsync <Dictionary <Uri, EntityId> >(topic); Dictionary <Uri, EntityId> observableDictionary = topicState.HasValue ? topicState.Value : new Dictionary <Uri, EntityId>(); if (observableDictionary.ContainsKey(entityId.EntityUri)) { return; } observableDictionary.Add(entityId.EntityUri, entityId); StringBuilder stringBuilder = new StringBuilder( $"Observer successfully registered.\r\n[Observable]: {entityId}\r\n[Observer]: {id}\r\n[Subscription]: Topic=[{topic}]"); int i = 1; foreach (string expression in expressions.Where(expression => !string.IsNullOrWhiteSpace(expression))) { stringBuilder.Append($" FilterExpression[{i++}]=[{expression}]"); } await this.StateManager.SetStateAsync(topic, observableDictionary); ActorEventSource.Current.Message(stringBuilder.ToString()); return; } 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; } await Task.Delay(ConfigurationHelper.BackoffQueryDelay); } throw new TimeoutException(Constants.RetryTimeoutExhausted); }