Introduction
In a previous article, I showed you how to delay execution via keyspace notifications of Redis in ASP.NET Core, and I will introduce another solution based on Redis.
Sorted Sets, a data structure of Redis, also can help us work it out.
We can make a timestamp as score, and the data as value. Sorted Sets provides a command that can return all the elements in the sorted set with a score between two special scores.
Setting 0 as the minimum score and current timestamp as the maximum score, we can get all the values whose timestamp are less than the current timestamp, and they should be executed at once and should be removed from Redis.
Taking a sample for more information.
Add some values at first.
- ZADD task:delay 1583546835 "180"
- ZADD task:delay 1583546864 "181"
- ZADD task:delay 1583546924 "182"
Suppose the current timestamp is 1583546860, so we can get all values via the following command.
- ZRANGEBYSCORE task:delay 0 1583546860 WITHSCORES LIMIT 0 1
We will get the value 180 from the above sample, and then we can do what we want to do.
Now, let's take a look at how to do this in ASP.NET Core.
Create Project
Create a new ASP.NET Core Web API project and install CSRedisCore.
- <ItemGroup>
- <PackageReference Include="CSRedisCore" Version="3.4.1" />
- </ItemGroup>
Add an interface named ITaskServices and a class named TaskServices.
- public interface ITaskServices
- {
- Task DoTaskAsync();
- Task SubscribeToDo();
- }
- public class TaskServices : ITaskServices
- {
- public async Task DoTaskAsync()
- {
- // do something here
- // ...
- // this operation should be done after some min or sec
- var cacheKey = "task:delay";
- int sec = new Random().Next(1, 5);
- var time = DateTimeOffset.Now.AddSeconds(sec).ToUnixTimeSeconds();
- var taskId = new Random().Next(1, 10000);
- await RedisHelper.ZAddAsync(cacheKey, (time, taskId));
- Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} done {taskId} here - {sec}");
- }
- public async Task SubscribeToDo()
- {
- var cacheKey = "task:delay";
- while (true)
- {
- var vals = RedisHelper.ZRangeByScore(cacheKey, -1, DateTimeOffset.Now.ToUnixTimeSeconds(), 1, 0);
- if (vals != null && vals.Length > 0)
- {
- var val = vals[0];
- // add a lock here may be more better
- var rmCount = RedisHelper.ZRem(cacheKey, vals);
- if (rmCount > 0)
- {
- Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} begin to do task {val}");
- }
- }
- else
- {
- await Task.Delay(500);
- }
- }
- }
- }


Join the conversation! Your thoughts help the community grow.