// 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);
}
}
}