public PublishSubscribeDistributedCache(string cacheGroup, IPublishSubscribe publishSubscribe) { _publishSubscribe = publishSubscribe ?? throw new ArgumentNullException(nameof(publishSubscribe)); MemoryCache memoryCache = new MemoryCache(new MemoryCacheOptions { CompactionPercentage = 0.1 }); _getTopic = cacheGroup + "_get"; _setTopic = cacheGroup + "_set"; _removeTopic = cacheGroup + "_remove"; publishSubscribe .Observe <byte[]>(_setTopic) .Subscribe(_ => { CacheEntry cacheEntry = CacheEntry.Parser.ParseFrom(_.Data); memoryCache.Set(cacheEntry.Key, cacheEntry); }, CancellationToken); publishSubscribe .Observe <string>(_removeTopic) .Subscribe(_ => { memoryCache.Remove(_.Data); }, CancellationToken); publishSubscribe .Observe <byte[]>(_getTopic) .Subscribe(_ => { CacheRequest cacheRequest = CacheRequest.Parser.ParseFrom(_.Data); CacheEntry value = memoryCache.Get <CacheEntry>(cacheRequest.Key) ?? new CacheEntry { Key = cacheRequest.Key }; publishSubscribe.Publish(cacheRequest.TopicResponse, value.ToByteArray()); }, CancellationToken); _selfTopic = Guid.NewGuid().ToString(); publishSubscribe .Observe <byte[]>(_selfTopic) .Subscribe(_ => { CacheEntry cacheEntry = CacheEntry.Parser.ParseFrom(_.Data); if (_completionSources.TryRemove(cacheEntry.Key, out TaskCompletionSource <byte[]> taskCompletionSource)) { taskCompletionSource.TrySetResult(cacheEntry.Value.ToByteArray()); } }, CancellationToken); }
public Task Initialize(TimeSpan timeout) { _subscription?.Dispose(); _subscription = _publishSubscribe .Observe <MessageData>(_queueId.ToString(), _queueId.ToString()) .Subscribe(tuple => { switch (tuple.Data) { case MessageData messageData: messageData.SerializationManager = _serializationManager; break; } _batchContainers.Enqueue(tuple.Data); }); return(Task.CompletedTask); }
public static IDisposable EnableDistributedBackplane(this IWampHostedRealm realm, IPublishSubscribe publishSubscribe) { ConcurrentDictionary <string, IDisposable> disposables = new ConcurrentDictionary <string, IDisposable>(); AtomicBoolean disableInternalPublishAtomicBoolean = new AtomicBoolean(); string forwarderPubSubTopic = $"DistributedRealm_{realm.Name}"; string selfId = $"{System.Diagnostics.Process.GetCurrentProcess().Id}_{Environment.MachineName}"; void TopicCreated(object sender, WampTopicCreatedEventArgs args) { IDisposable subscription = args.Topic .Subscribe(new PubSubForwarderWampRawTopicRouterSubscriber(selfId, forwarderPubSubTopic, args.Topic, publishSubscribe, disableInternalPublishAtomicBoolean)); disposables.TryAdd(args.Topic.TopicUri, subscription); } void TopicRemoved(object sender, WampTopicRemovedEventArgs args) { if (disposables.TryGetValue(args.Topic.TopicUri, out IDisposable subscription)) { subscription.Dispose(); } } realm.TopicContainer.TopicCreated += TopicCreated; realm.TopicContainer.TopicRemoved += TopicRemoved; PublishOptions defaultPublishOptions = new PublishOptions(); IDisposable pubSubSubscription = publishSubscribe .Observe <ForwardedWampMessage>(forwarderPubSubTopic) .Where(tuple => !selfId.Equals(tuple.Data.PublisherId)) .Subscribe(_ => { disableInternalPublishAtomicBoolean.FalseToTrue(); try { if (_.Data.ArgumentsKeywords == null && _.Data.Arguments == null) { realm.TopicContainer.Publish(WampObjectFormatter.Value, defaultPublishOptions, _.Data.WampTopic); } else { if (_.Data.ArgumentsKeywords == null) { realm.TopicContainer.Publish(WampObjectFormatter.Value, defaultPublishOptions, _.Data.WampTopic, _.Data.Arguments); } else { realm.TopicContainer.Publish(WampObjectFormatter.Value, defaultPublishOptions, _.Data.WampTopic, _.Data.Arguments, _.Data.ArgumentsKeywords); } } } finally { disableInternalPublishAtomicBoolean.TrueToFalse(); } }); return(new AnonymousDisposable(() => { pubSubSubscription.Dispose(); realm.TopicContainer.TopicCreated -= TopicCreated; realm.TopicContainer.TopicRemoved -= TopicRemoved; foreach (KeyValuePair <string, IDisposable> pair in disposables) { pair.Value.Dispose(); } })); }
public PublishSusbcribeCacheManagerBackplane( IPublishSubscribe publishSubscribe, ILoggerFactory loggerFactory, ICacheManagerConfiguration configuration) : base(configuration) { NotNull(configuration, nameof(publishSubscribe)); NotNull(loggerFactory, nameof(loggerFactory)); NotNull(loggerFactory, nameof(loggerFactory)); _publishSubscribe = publishSubscribe; _channelName = configuration.BackplaneChannelName ?? "CacheManagerBackplane"; _identifier = Encoding.UTF8.GetBytes(Guid.NewGuid().ToString()); ILogger logger = loggerFactory.CreateLogger(this); _subscription = publishSubscribe .Observe <byte[]>(_channelName) .SelectMany(serializedBackplaneMessage => BackplaneMessage.Deserialize(serializedBackplaneMessage.Data, _identifier)) .Subscribe(message => { if (logger.IsEnabled(LogLevel.Information)) { logger.LogInfo("Backplane got notified with new message."); } switch (message.Action) { case BackplaneAction.Clear: TriggerCleared(); break; case BackplaneAction.ClearRegion: TriggerClearedRegion(message.Region); break; case BackplaneAction.Changed: if (string.IsNullOrWhiteSpace(message.Region)) { TriggerChanged(message.Key, message.ChangeAction); } else { TriggerChanged(message.Key, message.Region, message.ChangeAction); } break; case BackplaneAction.Removed: if (string.IsNullOrWhiteSpace(message.Region)) { TriggerRemoved(message.Key); } else { TriggerRemoved(message.Key, message.Region); } break; } }); }