.net core 下使用 Kafka 延迟队列(四)
在电商业务中存在一个场景,用户生成订单,超过30分钟,将订单修改未支付,延迟队列就可以解决该场景问题
1 public class KafkaTopic 2 { 3 public static string Topic = "create-order"; 4 5 public static string DelayOrderTopic = "order-delay"; 6 }
1 /// <summary> 2 /// 延迟消费消息 3 /// </summary> 4 public void DelayReveice() 5 { 6 ConsumerConfig consumerConfig = this.CreateConsumerConnection(); 7 consumerConfig.AutoOffsetReset = AutoOffsetReset.Earliest; 8 consumerConfig.GroupId = "order";//分组为order组 9 //consumerConfig.FetchMinBytes = 170;//批量取:一次最少取多少消息大小 10 //consumerConfig.FetchMaxBytes = 3060;//批量取:一次最多取多少消息大小 11 var builder = new ConsumerBuilder<string, string>(consumerConfig); 12 using (var consumer = builder.Build()) 13 { 14 // 1、订阅 15 consumer.Subscribe(KafkaTopic.DelayOrderTopic); 16 // 2、偏移量恢复 17 string redisValue = this._distributedCache.GetString(KafkaTopic.DelayOrderTopic); 18 int offset = 0; 19 if (!string.IsNullOrEmpty(redisValue)) 20 { 21 offset = int.Parse(redisValue); 22 } 23 this._distributedCache.SetString(KafkaTopic.DelayOrderTopic, (offset + 1).ToString()); 24 25 //offset重置 26 //consumer.Assign(new TopicPartition(KafkaTopic.Topic, new Partition(1))); 27 consumer.Assign(new TopicPartitionOffset(KafkaTopic.DelayOrderTopic, new Partition(0), offset + 1)); 28 //循环消费消息 29 while (true) 30 { 31 // 1、恢复消息 32 new Timer((s) => 33 { 34 consumer.Resume(new List<TopicPartition> { new TopicPartition(KafkaTopic.DelayOrderTopic, new Partition(0)) }); 35 }, null, Timeout.Infinite, Timeout.Infinite).Change(60*1000, 60*5000);//5秒之后回复 36 37 //Change(int dueTime, int period) 38 //dueTime:在首次调用回调方法之前要等待多少毫秒。 39 // 如希望立刻调用回调方法, 40 // 该参数指定为0即可。 41 //period:指定了以后每次调用回调方法之前要等待多少毫秒 42 // (理解成下一次和本次调用的时间间隔即可)。 43 // 如果为该参数传递Timeout.Infinite(或者直接写 - 1), 44 // 线程池线程只调用回调方法一次(那也就没有必要用计时器了)。 45 46 // 1.1、消费暂停 47 consumer.Pause(new List<TopicPartition> { new TopicPartition(KafkaTopic.DelayOrderTopic, new Partition(0)) }); 48 49 // 2、消费消息 50 var result = consumer.Consume(); //批量获取消息,根据-----》字节数 51 try 52 { 53 // 2.1、获取偏移量 54 _logger.LogInformation($"订单消息偏移量:Offset:{result.Offset}"); 55 // 3、业务处理 56 string key = result.Key; 57 string value = result.Value; 58 _logger.LogInformation($"创建商品:Key:{key}"); 59 _logger.LogInformation($"创建商品:Order:{value}"); 60 // redis存储 kafka队列的偏移量 61 _distributedCache.SetString(KafkaTopic.DelayOrderTopic, result.Offset.Value.ToString()); 62 } 63 catch (Exception) 64 { 65 66 throw; 67 } 68 finally 69 { 70 consumer.Pause(new List<TopicPartition> { new TopicPartition(KafkaTopic.DelayOrderTopic, 0) }); 71 Console.WriteLine($"暂停消费"); 72 } 73 } 74 } 75 }
调用延迟消费
1 using KafkaCommom; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace KafKaWorker 9 { 10 public class DelayReveiceWorker : BackgroundService 11 { 12 private readonly ILogger<Worker> _logger; 13 private readonly KafKaSevice _kafKaSevice; 14 public DelayReveiceWorker(ILogger<Worker> logger, KafKaSevice kafKaSevice) 15 { 16 _logger = logger; 17 _kafKaSevice = kafKaSevice; 18 } 19 20 protected override async Task ExecuteAsync(CancellationToken stoppingToken) 21 { 22 _kafKaSevice.DelayReveice(); 23 await Task.CompletedTask; 24 } 25 } 26 }
webapi 调用发送消息
1 /// <summary> 2 /// 发送消息 3 /// </summary> 4 /// <param name="msg"></param> 5 /// <returns></returns> 6 [HttpGet] 7 public string Get(string msg) 8 { 9 this._kafKaSevice.Send(msg); 10 return ""; 11 }
测试消费 现在每隔 1分钟消费一次 做到了延迟消费