// Copyright Epic Games, Inc. All Rights Reserved. using System; using System.Threading; using System.Threading.Tasks; using EpicGames.Core; using StackExchange.Redis; namespace EpicGames.Redis { /// /// Distributed version of . The event will be pulsed via a pub/sub channel in Redis. /// public sealed class RedisEvent : IAsyncDisposable { readonly IConnectionMultiplexer _multiplexer; readonly RedisChannel _channel; readonly AsyncEvent _asyncEvent; readonly RedisSubscription _subscription; /// /// Accessor for the inner task. Can be captured and awaited by clients. /// public Task Task => _asyncEvent.Task; RedisEvent(IConnectionMultiplexer multiplexer, RedisChannel channel, AsyncEvent asyncEvent, RedisSubscription subscription) { _multiplexer = multiplexer; _channel = channel; _asyncEvent = asyncEvent; _subscription = subscription; } /// public ValueTask DisposeAsync() => _subscription.DisposeAsync(); /// /// Create a new async event using the given channel name /// /// Multiplexer for the /// Channel for posting event updates /// Cancellation token for the operation /// public static async Task CreateAsync(IConnectionMultiplexer multiplexer, RedisChannel channel, CancellationToken cancellationToken = default) { AsyncEvent asyncEvent = new AsyncEvent(); RedisSubscription subscription = await multiplexer.SubscribeAsync(channel, x => asyncEvent.Pulse()); if (cancellationToken.IsCancellationRequested) { await subscription.DisposeAsync(); cancellationToken.ThrowIfCancellationRequested(); } return new RedisEvent(multiplexer, channel, asyncEvent, subscription); } /// /// Pulse the event, allowing any captured copies of the task to continue. /// public void Pulse() { _ = _multiplexer.GetDatabase().PublishAsync(_channel, RedisValue.EmptyString, CommandFlags.FireAndForget); } } }