public async Task <string> Watch <T>(string actorInterface, string eventName, string actorId, Action <ActorEvent <T> > handler) { var channel = ActorEventChannel(actorInterface, eventName, actorId); SubscriptionHandler action = (string c, ref byte[] data) => { var e = new ActorEvent <T>() { ActorInterface = actorInterface, EventName = eventName, EventData = _serializer.Deserialize <T>(data), ActorId = c.Split(':').Last() }; handler(e); }; var guid = Guid.NewGuid().ToString(); _subscriptions[guid] = new PubSubSubscription() { Channel = channel, Handler = action }; await _pubsub.Subscribe(channel, action); return(guid); }
public static async Task <TResponse> RequestAsync <TRequest, TResponse>(this IPubSub pubsub, TRequest message, TimeSpan timeout, bool self = true) { var request = new Request <TRequest> { Body = message, CorrelationId = Guid.NewGuid() }; IDisposable subscription = null; try { var receiveTask = new TaskCompletionSource <TResponse>(TaskCreationOptions.RunContinuationsAsynchronously); subscription = pubsub.Subscribe <Response <TResponse> >(response => { if (response.CorrelationId == request.CorrelationId) { receiveTask.SetResult(response.Body); } }); Task.Run(() => pubsub.Publish(request, self)); using (var cts = new CancellationTokenSource(timeout)) { return(await receiveTask.Task.WithCancellation(cts.Token)); } } finally { subscription?.Dispose(); } }
public async Task Should_write_to_store_with_previous_version() { InvalidateMessage message = null; pubSub.Subscribe <InvalidateMessage>(m => { message = m; }); A.CallTo(() => snapshotStore.ReadAsync(key)) .Returns((123, 13)); var actualObject = await sut.GetSingleAsync <MyStatefulObject, string>(key); Assert.Same(statefulObject, actualObject); Assert.Equal(123, statefulObject.State); statefulObject.SetState(456); await statefulObject.WriteStateAsync(); A.CallTo(() => snapshotStore.WriteAsync(key, 456, 13, 14)) .MustHaveHappened(); Assert.NotNull(message); Assert.Equal(key, message.Key); }
public async Task Should_write_to_store_with_previous_etag() { var etag = Guid.NewGuid().ToString(); InvalidateMessage message = null; pubSub.Subscribe <InvalidateMessage>(m => { message = m; }); A.CallTo(() => store.ReadAsync <int>(key)) .Returns((123, etag)); var actual = await sut.GetAsync <MyStatefulObject, int>(key); Assert.Same(state, actual); Assert.Equal(123, state.State); state.SetState(456); await state.WriteStateAsync(); A.CallTo(() => store.WriteAsync(key, 456, etag, A <string> .That.Matches(x => x != null))) .MustHaveHappened(); Assert.NotNull(message); Assert.Equal(key, message.Key); }
public async Task Should_write_to_store_with_previous_position() { InvalidateMessage message = null; pubSub.Subscribe <InvalidateMessage>(m => { message = m; }); SetupEventStore(3); var actualObject = await sut.GetSingleAsync <MyStatefulObject>(key); Assert.Same(statefulObject, actualObject); await statefulObject.WriteEventsAsync(new MyEvent(), new MyEvent()); await statefulObject.WriteEventsAsync(new MyEvent(), new MyEvent()); A.CallTo(() => eventStore.AppendEventsAsync(A <Guid> .Ignored, key, 2, A <ICollection <EventData> > .That.Matches(x => x.Count == 2))) .MustHaveHappened(); A.CallTo(() => eventStore.AppendEventsAsync(A <Guid> .Ignored, key, 4, A <ICollection <EventData> > .That.Matches(x => x.Count == 2))) .MustHaveHappened(); Assert.NotNull(message); Assert.Equal(key, message.Key); }
public override void InitializePresenter(dynamic context) { _view = (IQueryWindowControl)context.QueryWindowControl; _view.Presenter = this; _pubsub = context.PubSub; _pubsub.Subscribe(this, Constants.SubscriptionTypes.THEME_CHANGE); TabIndexReference = (int)context.TabIndexReference; }
public void InitializePresenter(dynamic context) { _context = context; _view = (IActionLogForm)context.ActionLogForm; _view.Presenter = this; _pubsub = context.PubSub; _pubsub.Subscribe(this, Constants.SubscriptionTypes.THEME_CHANGE); }
public void InitializePresenter(dynamic context) { _context = context; _view = (IMainForm)context.MainForm; _view.Presenter = this; _pubsub = context.PubSub; _pubsub.Subscribe(this, Constants.SubscriptionTypes.THEME_CHANGE); InitializeTransactionCache(); }
public void Initialize() { pubSubSubscription = pubSub.Subscribe <InvalidateMessage>(m => { lock (lockObject) { statesCache.Remove(m.Key); } }); }
public InvalidatingMemoryCache(IMemoryCache inner, IPubSub invalidator) { Guard.NotNull(inner, nameof(inner)); Guard.NotNull(invalidator, nameof(invalidator)); this.inner = inner; this.invalidator = invalidator; invalidator.Subscribe(ChannelName, inner.Remove); }
public static IDisposable ReceiveAsync <TRequest, TResponse>(this IPubSub pubsub, Func <TRequest, Task <TResponse> > callback, bool self = true) { return(pubsub.Subscribe <Request <TRequest> >(async x => { var response = await callback(x.Body); pubsub.Publish(new Response <TResponse> { CorrelationId = x.CorrelationId, Body = response }, true); })); }
public InvalidatingMemoryCache(IMemoryCache inner, IPubSub invalidator) { Guard.NotNull(inner, nameof(inner)); Guard.NotNull(invalidator, nameof(invalidator)); this.inner = inner; this.invalidator = invalidator; subscription = invalidator.Subscribe <InvalidateMessage>(m => { inner.Remove(m.CacheKey); }); }
public void Should_send_invalidation_message_on_refresh() { InvalidateMessage message = null; pubSub.Subscribe <InvalidateMessage>(m => { message = m; }); sut.Synchronize <MyStatefulObject, string>(key); Assert.NotNull(message); Assert.Equal(key, message.Key); }
/// <summary> /// Subscribes to a stream of messages that match a .NET type. /// </summary> /// <typeparam name="T">The type to subscribe to</typeparam> /// <param name="pubSub">The pubSub instance</param> /// <param name="subscriptionId"> /// A unique identifier for the subscription. Two subscriptions with the same subscriptionId /// and type will get messages delivered in turn. This is useful if you want multiple subscribers /// to load balance a subscription in a round-robin fashion. /// </param> /// <param name="onMessage"> /// The action to run when a message arrives. When onMessage completes the message /// receipt is Ack'd. All onMessage delegates are processed on a single thread so you should /// avoid long running blocking IO operations. Consider using SubscribeAsync /// </param> /// <param name="cancellationToken">The cancellation token</param> /// <returns> /// An <see cref="ISubscriptionResult"/> /// Call Dispose on it or on its <see cref="ISubscriptionResult.ConsumerCancellation"/> to cancel the subscription. /// </returns> public static ISubscriptionResult Subscribe <T>( this IPubSub pubSub, string subscriptionId, Action <T> onMessage, CancellationToken cancellationToken = default ) { Preconditions.CheckNotNull(pubSub, "pubSub"); return(pubSub.Subscribe( subscriptionId, onMessage, c => { }, cancellationToken )); }
/// <summary> /// Subscribes to a stream of messages that match a .NET type. /// Allows the subscriber to complete asynchronously. /// </summary> /// <typeparam name="T">The type to subscribe to</typeparam> /// <param name="pubSub">The pubSub instance</param> /// <param name="subscriptionId"> /// A unique identifier for the subscription. Two subscriptions with the same subscriptionId /// and type will get messages delivered in turn. This is useful if you want multiple subscribers /// to load balance a subscription in a round-robin fashion. /// </param> /// <param name="onMessage"> /// The action to run when a message arrives. onMessage can immediately return a Task and /// then continue processing asynchronously. When the Task completes the message will be /// Ack'd. /// </param> /// <param name="cancellationToken">The cancellation token</param> /// <returns> /// An <see cref="ISubscriptionResult"/> /// Call Dispose on it or on its <see cref="ISubscriptionResult.ConsumerCancellation"/> to cancel the subscription. /// </returns> public static ISubscriptionResult Subscribe <T>( this IPubSub pubSub, string subscriptionId, Func <T, Task> onMessage, CancellationToken cancellationToken = default ) { Preconditions.CheckNotNull(pubSub, "pubSub"); return(pubSub.Subscribe <T>( subscriptionId, (m, c) => onMessage(m), c => { }, cancellationToken )); }
public void Subscribe(string recipient, Action <object> handler) { Guard.NotNullOrEmpty(recipient, nameof(recipient)); pubSub.Subscribe(ChannelName, json => { var envelope = JsonConvert.DeserializeObject <Envelope>(json); if (string.Equals(envelope.Recipient, recipient, StringComparison.OrdinalIgnoreCase)) { var messageType = typeNameRegistry.GetType(envelope.PayloadType); var messageBody = ReadJson(envelope.Payload, messageType); handler?.Invoke(messageBody); } }); }
public async Task SubscribeAsync(Func <PunchyMessage, Task> onMessageAsync, string groupId, CancellationToken cancellationToken, params string[] topics) { if (onMessageAsync == null) { throw new ArgumentNullException(nameof(onMessageAsync)); } if (groupId == null) { throw new ArgumentNullException(nameof(groupId)); } if (!TopicNameHelpers.IsValid(groupId)) { throw new ArgumentException( $"The groupId must match regex pattern: '{TopicNameHelpers.TopicOrGroupIdValidationRegexPattern}'", nameof(groupId)); } var messageHandler = new MessageHandler(onMessageAsync, pubSub, logger, configuration, groupId); var retryerTopics = new List <string>(); foreach (var topic in topics) { if (!TopicNameHelpers.IsValid(topic)) { throw new ArgumentException( $"The topic name must match regex pattern: '{TopicNameHelpers.TopicOrGroupIdValidationRegexPattern}'. " + $"Validation failed for '{topic}'.", nameof(topics)); } if (!TopicNameHelpers.IsBadMessageTopic(topic)) { for (int i = 0; i < configuration.LevelDelaysInSeconds.Length; i++) { retryerTopics.Add(TopicNameHelpers.BuildBadMessageTopicName(topic, i, groupId)); } } } var subscription = pubSub.Subscribe(messageHandler, groupId, topics.Union(retryerTopics).ToArray()); messageHandler.Subscription = subscription; await subscription.StartAsync(cancellationToken); }
/// <summary> /// Subscribes to a stream of messages that match a .NET type. /// </summary> /// <typeparam name="T">The type to subscribe to</typeparam> /// <param name="pubSub">The pubSub instance</param> /// <param name="subscriptionId"> /// A unique identifier for the subscription. Two subscriptions with the same subscriptionId /// and type will get messages delivered in turn. This is useful if you want multiple subscribers /// to load balance a subscription in a round-robin fashion. /// </param> /// <param name="onMessage"> /// The action to run when a message arrives. When onMessage completes the message /// receipt is Ack'd. All onMessage delegates are processed on a single thread so you should /// avoid long running blocking IO operations. Consider using SubscribeAsync /// </param> /// <param name="configure"> /// Fluent configuration e.g. x => x.WithTopic("uk.london") /// </param> /// <param name="cancellationToken">The cancellation token</param> /// <returns> /// An <see cref="ISubscriptionResult"/> /// Call Dispose on it or on its <see cref="ISubscriptionResult.ConsumerCancellation"/> to cancel the subscription. /// </returns> public static ISubscriptionResult Subscribe <T>( this IPubSub pubSub, string subscriptionId, Action <T> onMessage, Action <ISubscriptionConfiguration> configure, CancellationToken cancellationToken = default ) { Preconditions.CheckNotNull(pubSub, "pubSub"); var onMessageAsync = TaskHelpers.FromAction <T>((m, c) => onMessage(m)); return(pubSub.Subscribe( subscriptionId, onMessageAsync, configure, cancellationToken )); }
public static async Task <TResponse> RequestAsync <TRequest, TResponse>(this IPubSub pubsub, TRequest message, TimeSpan timeout, bool self = true) { var request = new Request <TRequest> { Body = message, CorrelationId = Guid.NewGuid() }; IDisposable subscription = null; try { var receiveTask = new TaskCompletionSource <TResponse>(); subscription = pubsub.Subscribe <Response <TResponse> >(response => { if (response.CorrelationId == request.CorrelationId) { receiveTask.SetResult(response.Body); } }); Task.Run(() => pubsub.Publish(request, self)); var firstTask = await Task.WhenAny(receiveTask.Task, Task.Delay(timeout)); if (firstTask.Id != receiveTask.Task.Id) { throw new TaskCanceledException(); } else { return(await receiveTask.Task); } } finally { subscription?.Dispose(); } }
public IDisposable Subscribe(Action handler) { return(invalidator.Subscribe(ChannelName, x => handler())); }
public IDisposable Subscribe(Action <string> handler) { return(pubsub.Subscribe <EventNotification>(x => handler?.Invoke(x.StreamName))); }
public void Init(IPubSub pubSub) { pubSub.Subscribe <FileReadProgressEvent>(ProgressUpdaterDelegate); }
/// <summary> /// 订阅 /// </summary> /// <param name="channel"></param> /// <param name="action"></param> public void Subscribe(string channel, Action <string> action) { pubsub.Subscribe(channel, action); }
public void PublishSimpleTest() { var recorder = new Recorder <int>(); _pubSub.Subscribe("/temperature", recorder.Handler); _pubSub.Publish("/temperature", 25); var expected = Tuple.Create("/temperature", 25); recorder.Messages.Should() .ContainSingle(tuple => Equals(tuple, expected)); }
public IDisposable Subscribe(Action <string> handler) { return(pubsub.Subscribe(ChannelName, x => handler?.Invoke(x))); }
public void Subscribe(Action handler) { invalidator.Subscribe(ChannelName, x => handler()); }