Add EventPriority

This commit is contained in:
Haiping Chen 2024-11-22 22:38:09 -06:00
parent 0d95262bb3
commit 11ceb8e013
4 changed files with 63 additions and 29 deletions

View file

@ -0,0 +1,8 @@
namespace BotSharp.Abstraction.Infrastructures.Enums;
public enum EventPriority
{
Low = 1,
Medium = 2,
High = 3
}

View file

@ -10,7 +10,7 @@ public interface IEventPublisher
/// <returns></returns>
Task BroadcastAsync(string channel, string message);
Task PublishAsync(string channel, string message);
Task PublishAsync(string channel, string message, EventPriority priority = EventPriority.Medium);
Task ReDispatchAsync(string channel, int count = 10, string order = "asc");

View file

@ -1,3 +1,4 @@
using BotSharp.Abstraction.Infrastructures.Enums;
using StackExchange.Redis;
namespace BotSharp.Core.Infrastructures.Events;
@ -20,10 +21,13 @@ public class RedisPublisher : IEventPublisher
await _subscriber.PublishAsync(channel, message);
}
public async Task PublishAsync(string channel, string message)
public async Task PublishAsync(string channel, string message, EventPriority priority = EventPriority.Medium)
{
var db = _redis.GetDatabase();
// convert to apporiate channel by priority
channel = $"{channel}-{priority}";
if (CheckMessageExists(db, channel, "message", message))
{
_logger.LogError($"The message already exists {channel} {message}");
@ -41,7 +45,7 @@ public class RedisPublisher : IEventPublisher
_logger.LogInformation($"Published message {channel} {message} ({messageId})");
}
private bool CheckMessageExists(IDatabase db, string streamName, string fieldName, string desiredValue)
private bool CheckMessageExists(IDatabase db, string channel, string fieldName, string desiredValue)
{
// Define the range to fetch all messages
RedisValue start = "-"; // Start from the smallest ID
@ -49,7 +53,7 @@ public class RedisPublisher : IEventPublisher
int count = 10; // Number of messages to retrieve
// Fetch the latest 10 messages
var streamEntries = db.StreamRange(streamName, start, end, count, Order.Descending);
var streamEntries = db.StreamRange(channel, start, end, count, Order.Descending);
if (streamEntries.Length == 0)
{

View file

@ -1,3 +1,4 @@
using BotSharp.Abstraction.Infrastructures.Enums;
using StackExchange.Redis;
namespace BotSharp.Core.Infrastructures.Events;
@ -28,6 +29,52 @@ public class RedisSubscriber : IEventSubscriber
{
var db = _redis.GetDatabase();
await CreateConsumerGroup(db, $"{channel}-{EventPriority.Low}", group);
await CreateConsumerGroup(db, $"{channel}-{EventPriority.Medium}", group);
await CreateConsumerGroup(db, $"{channel}-{EventPriority.High}", group);
while (true)
{
if (await HandleGroupMessage(db, $"{channel}-{EventPriority.High}", group, received) > 0)
{
continue;
}
if (await HandleGroupMessage(db, $"{channel}-{EventPriority.Medium}", group, received) > 0)
{
continue;
}
await HandleGroupMessage(db, $"{channel}-{EventPriority.Low}", group, received);
}
}
private async Task<int> HandleGroupMessage(IDatabase db, string channel, string group, Func<string, string, Task> received)
{
var entries = await db.StreamReadGroupAsync(channel, group, Environment.MachineName, count: 1);
foreach (var entry in entries)
{
_logger.LogInformation($"Consumer {Environment.MachineName} received: {channel} {entry.Values[0].Value}");
await db.StreamAcknowledgeAsync(channel, group, entry.Id);
try
{
await received(channel, entry.Values[0].Value);
// Optionally delete the message to save space
await db.StreamDeleteAsync(channel, [entry.Id]);
}
catch (Exception ex)
{
_logger.LogError($"Error processing message: {ex.Message}, event id: {channel} {entry.Id}\r\n{ex}");
}
}
return entries.Length;
}
private async Task CreateConsumerGroup(IDatabase db, string channel, string group)
{
// Create the consumer group if it doesn't exist
try
{
@ -43,30 +90,5 @@ public class RedisSubscriber : IEventSubscriber
_logger.LogError($"Error creating consumer group: '{group}' {ex.Message}");
throw;
}
while (true)
{
var entries = await db.StreamReadGroupAsync(channel, group, Environment.MachineName, count: 1);
foreach (var entry in entries)
{
_logger.LogInformation($"Consumer {Environment.MachineName} received: {channel} {entry.Values[0].Value}");
await db.StreamAcknowledgeAsync(channel, group, entry.Id);
try
{
await received(channel, entry.Values[0].Value);
// Optionally delete the message to save space
await db.StreamDeleteAsync(channel, [entry.Id]);
}
catch (Exception ex)
{
_logger.LogError($"Error processing message: {ex.Message}, event id: {channel} {entry.Id}\r\n{ex}");
}
}
await Task.Delay(Random.Shared.Next(1, 11) * 100);
}
}
}