ASP.NET Core redis延迟队列

作者 : 慕源网 本文共3152个字,预计阅读时间需要8分钟 发布时间: 2022-04-27 共251人阅读

redis延迟队列由于某些业务需求,许多操作不应该立即开始执行;它们应该在几秒钟、几分钟或几小时后开始。

例如,假设有一个任务,它包含两个步骤。当我们完成第一步后,第二步应该在 5 分钟后开始。

我们如何解决这个问题?

Thread.Sleep()Task.Delay()是非常简单的解决方案。但它会阻止我们的应用程序。

而在本文中,我将介绍一种基于Redis的 keyspace notifications 的解决方案。

我们将使用过期事件来做,这个解决方案也有一些限制,因为它可能会有很大的延迟。延迟执行可能有smoe错误,并且不会很准确!

我们来看看这个解决方案。 

设置 Redis

Keyspace notifications 是从 2.8.0 开始提供的功能,所以 Redis 的版​​本应该不低于 2.8.0。

我们需要修改一个重要的配置,以便我们可以启用此功能。

#############################活动通知################## ###########  
 
# Redis 可以通知 Pub/Sub 客户端有关密钥空间中发生的事件。  
# 此功能记录在 http://redis.io/topics/notifications  
#  
#…………  
#  
# 默认情况下,所有通知都被禁用,因为大多数用户不需要  
# 这个特性和特性有一些开销。请注意,如果您不  
# 至少指定 K 或 E 之一,不会传递任何事件。  
notify-keyspace-events ""  

notify-keyspace-events 的默认值为空,我们应该将其修改为 Ex。

notify-keyspace-events "Ex"  
然后我们就可以启动 Redis 服务器了。

ASP.NET Core redis延迟队列

创建项目

创建一个新的 ASP.NET Core Web API 项目并安装CSRedisCore。

<Project Sdk="Microsoft.NET.Sdk.Web">  
  
  <PropertyGroup>  
    <TargetFramework>netcoreapp3.1</TargetFramework>  
  </PropertyGroup>  
  
  <ItemGroup>  
    <PackageReference Include="CSRedisCore" Version="3.4.1" />  
  </ItemGroup>  
  
</Project> 

添加一个名为 ITaskServices 的接口和一个名为 TaskServices 的类。

public interface ITaskServices  
{  
    void SubscribeToDo(string keyPrefix);  
  
    Task DoTaskAsync();  
}  
  
public class TaskServices : ITaskServices  
{  
    public async Task DoTaskAsync()  
    {  
        // do something here  
        // ...  
  
        // this operation should be done after some min or sec  
        var taskId = new Random().Next(1, 10000);  
        int sec = new Random().Next(1, 5);  
  
        await RedisHelper.SetAsync($"task:{taskId}", "1", sec);  
        await RedisHelper.SetAsync($"other:{taskId + 10000}", "1", sec);  
    }  
  
    public void SubscribeToDo(string keyPrefix)  
    {  
        RedisHelper.Subscribe(  
            ("__keyevent@0__:expired", arg =>  
                {  
                    var msg = arg.Body;  
                    Console.WriteLine($"recive {msg}");  
                    if (msg.StartsWith(keyPrefix))  
                    {  
                        // read the task id from expired key  
                        var val = msg.Substring(keyPrefix.Length);  
                        Console.WriteLine($"Redis + Subscribe {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} begin to do task {val}");  
                    }  
                })  
        );  
    }  
}

如您所见,我们设置了一个具有过期时间的 redis 键。过期是延迟时间。

对于延迟执行,我们可以在SubscribeToDo方法中找到它。它订阅了一个名为 __keyevent@0__:expired 的channel。

当某个key过期时,redis server会向这个channel发布消息,订阅者会收到。

收到通知后,客户端将开始工作。

在客户端收到通知之前,延迟作业不会被执行,这样可以帮助我们做延迟作业。

这里是这个操作的入口。

[ApiController]  
[Route("api/tasks")]  
public class TaskController : ControllerBase  
{  
    private readonly ITaskServices _svc;  
  
    public TaskController(ITaskServices svc)  
    {  
        _svc = svc;  
    }  
  
    [HttpGet]  
    public async Task<string> Get()  
    {  
        await _svc.DoTaskAsync();  
        System.Console.WriteLine("done here");  
        return "done";  
    }  
}  
将订阅者放入 BackgroundService,以便它可以在后台运行。
public class SubscribeTaskBgTask : BackgroundService  
{  
    private readonly ILogger _logger;  
    private readonly ITaskServices _taskServices;  
  
    public SubscribeTaskBgTask(ILoggerFactory loggerFactory, ITaskServices taskServices)  
    {  
        this._logger = loggerFactory.CreateLogger<RefreshCachingBgTask>();  
        this._taskServices = taskServices;  
    }  
  
    protected override Task ExecuteAsync(CancellationToken stoppingToken)  
    {  
        stoppingToken.ThrowIfCancellationRequested();  
  
        _taskServices.SubscribeToDo("task:");  
  
        return Task.CompletedTask;  
    }  
} 
最后,我们应该在启动类中注册上述服务。
public class Startup  
{  
    // ...  
      
    public void ConfigureServices(IServiceCollection services)  
    {  
        var csredis = new CSRedis.CSRedisClient("127.0.0.1:6379");  
        RedisHelper.Initialization(csredis);  
  
        services.AddSingleton<ITaskServices, TaskServices>();  
        services.AddHostedService<SubscribeTaskBgTask>();  
  
        services.AddControllers();  
    }  
}

这是运行此应用程序后的结果。

ASP.NET Core redis延迟队列

这是您可以在我的 GitHub 页面中找到的源代码。

总结

本文向您展示了如何使用 Redis Keyspace Notifications 在 ASP.NET Core 中延迟执行的简单解决方案。

我希望这能帮到您!


慕源网 » ASP.NET Core redis延迟队列

常见问题FAQ

程序仅供学习研究,请勿用于非法用途,不得违反国家法律,否则后果自负,一切法律责任与本站无关。
请仔细阅读以上条款再购买,拍下即代表同意条款并遵守约定,谢谢大家支持理解!

发表评论

开通VIP 享更多特权,建议使用QQ登录