.Net之延遲隊列

介紹

具有隊列的特性,再給它附加一個延遲消費隊列消息的功能,也就是說可以指定隊列中的消息在哪個時間點被消費。

使用場景

延遲隊列在項目中的應用還是比較多的,尤其像電商類平臺:

  1. 訂單成功后,在30分鐘內沒有支付,自動取消訂單

  2. 外賣平臺發送訂餐通知,下單成功后60s給用戶推送短信。

  3. 如果訂單一直處于某一個未完結狀態時,及時處理關單,并退還庫存

  4. 淘寶新建商戶一個月內還沒上傳商品信息,將凍結商鋪等

該介紹來自其他文章

方案

下面的例子沒有進行封裝,所以代碼僅供參考

Redis過期事件

注意:

不保證在設定的過期時間立即刪除并發送通知,數據量大的時候會延遲比較大

不保證一定送達

發送即忘策略,不包含持久化

但是比如有些場景,對這個時間不是那么看重,并且有其他措施雙層保障,該實現方案是比較簡單。

redis自2.8.0之后版本提供Keyspace Notifications功能,允許客戶訂閱Pub / Sub頻道,以便以某種方式接收影響Redis數據集事件。

配置

需要修改配置啟用過期事件,比如在windows客戶端中,需要修改redis.windows.conf文件,在linux中需要修改redis.conf,修改內容是:

6a43c54fda240392d4b4e9892090fbbf.png
img
--?取消注釋
notify-keyspace-events?Ex--?注釋
#notify-keyspace-events?""

然后重新啟動服務器,比如windows

.\redis-server.exe  .\redis.windows.conf

或者linux中使用docker-compose重新部署redis

redis:container_name:?redisimage:?redishostname:?redisrestart:?alwaysports:?-?"6379:6379"volumes:?-?$PWD/redis/redis.conf:/etc/redis.conf-?/root/common-docker-compose/redis/data:/datacommand:?/bin/bash?-c?"redis-server?/etc/redis.conf"?#啟動執行指定的redis.conf文件

然后使用客戶端訂閱事件

--?windows
.\redis-cli--?linux
docker?exec?-it?容器標識?redis-clipsubscribe?__keyevent@0__:expired

控制臺訂閱

使用StackExchange.Redis組件訂閱過期事件

var?connectionMultiplexer?=?ConnectionMultiplexer.Connect(_redisConnection);
var?db?=?connectionMultiplexer.GetDatabase(0);db.StringSet("orderno:123456",?"訂單創建",?TimeSpan.FromSeconds(10));
Console.WriteLine("開始訂閱");var?subscriber?=?connectionMultiplexer.GetSubscriber();//訂閱庫0的過期通知事件
subscriber.Subscribe("__keyevent@0__:expired",?(channel,?key)?=>
{Console.WriteLine($"key過期?channel:{channel}?key:{key}");
});Console.ReadLine();

輸出結果:

key過期 channel:keyevent@0:expired key:orderno:123456

如果啟動多個客戶端監聽,那么多個客戶端都可以收到過期事件。

WebApi中訂閱

創建RedisListenService繼承自:BackgroundService

public?class?RedisListenService?:?BackgroundService
{private?readonly?ISubscriber?_subscriber;public?RedisListenService(IServiceScopeFactory?serviceScopeFactory){using?var?scope?=?serviceScopeFactory.CreateScope();var?configuration?=?scope.ServiceProvider.GetRequiredService<IConfiguration>();var?connectionMultiplexer?=?ConnectionMultiplexer.Connect(configuration["redis"]);var?db?=?connectionMultiplexer.GetDatabase(0);_subscriber?=?connectionMultiplexer.GetSubscriber();}protected?override?Task?ExecuteAsync(CancellationToken?stoppingToken){//訂閱庫0的過期通知事件_subscriber.Subscribe("__keyevent@0__:expired",?(channel,?key)?=>{Console.WriteLine($"key過期?channel:{channel}?key:{key}");});return?Task.CompletedTask;}
}

注冊該后臺服務

services.AddHostedService<RedisListenService>();

啟用項目,給redis指定庫設置值,等過期后會接收到過期通知事件。

RabbitMq延遲隊列

版本信息 ? Rabbitmq版本:3.10.5 ?Erlang版本:24.3.4.2

要使用rabbitmq做延遲是需要安裝插件(rabbitmq_delayed_message_exchange)的

插件介紹:https://blog.rabbitmq.com/posts/2015/04/scheduling-messages-with-rabbitmq

下載地址:https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases

將下載好的插件(d:/Download/rabbitmq_delayed_message_exchange-3.10.2.ez)映射到容器的plugins目錄下:

docker?run?-d?--name?myrabbit?-p?9005:15672?-p?5672:5672??-e?RABBITMQ_DEFAULT_VHOST=customer?-e?RABBITMQ_DEFAULT_USER=admin?-e?RABBITMQ_DEFAULT_PASS=123456?-v?d:/Download/rabbitmq_delayed_message_exchange-3.10.2.ez:/plugins/rabbitmq_delayed_message_exchange-3.10.2.ez??rabbitmq:3-management-alpine

進入容器

docker?exec?-it?容器名稱/標識?bash

啟用插件

rabbitmq-plugins?enable?rabbitmq_delayed_message_exchange

查看是否啟用

rabbitmq-plugins?list

[E*]和[e*]表示啟用,然后重啟服務

rabbitmq-server?restart

然后在管理界面添加交換機都可以看到

940d9c684ce4664ad0b16c61eb456085.png
img

生產消息

發送的消息類型是:x-delayed-message

[HttpGet("send/delay")]
public?string?SendDelayedMessage()
{var?factory?=?new?ConnectionFactory(){HostName?=?"localhost",//IP地址Port?=?5672,//端口號UserName?=?"admin",//用戶賬號Password?=?"123456",//用戶密碼VirtualHost?=?"customer"};using?var?connection?=?factory.CreateConnection();using?var?channel?=?connection.CreateModel();var?exchangeName?=?"delay-exchange";var?routingkey?=?"delay.delay";var?queueName?=?"delay_queueName";//設置Exchange隊列類型var?argMaps?=?new?Dictionary<string,?object>(){{"x-delayed-type",?"topic"}};//設置當前消息為延時隊列channel.ExchangeDeclare(exchange:?exchangeName,?type:?"x-delayed-message",?true,?false,?argMaps);channel.QueueDeclare(queueName,?true,?false,?false,?argMaps);channel.QueueBind(queueName,?exchangeName,?routingkey);var?time?=?1000?*?5;var?message?=?$"發送時間為?{DateTime.Now:yyyy-MM-dd?HH:mm:ss}?延時時間為:{time}";var?body?=?Encoding.UTF8.GetBytes(message);var?props?=?channel.CreateBasicProperties();//設置消息的過期時間props.Headers?=?new?Dictionary<string,?object>(){{??"x-delay",?time?}};channel.BasicPublish(exchange:?exchangeName,?routingKey:?routingkey,?basicProperties:?props,?body:?body);Console.WriteLine("成功發送消息:"?+?message);return?"success";
}

消費消息

消費消息我是弄了一個后臺任務(RabbitmqDelayedHostService)在處理

public?class?RabbitmqDelayedHostService?:?BackgroundService
{private?readonly?IModel?_channel;private?readonly?IConnection?_connection;public?RabbitmqDelayedHostService(){var?connFactory?=?new?ConnectionFactory//創建連接工廠對象{HostName?=?"localhost",//IP地址Port?=?5672,//端口號UserName?=?"admin",//用戶賬號Password?=?"123456",//用戶密碼VirtualHost?=?"customer"};_connection?=?connFactory.CreateConnection();_channel?=?_connection.CreateModel();//交換機名稱var?exchangeName?=?"exchangeDelayed";var?queueName?=?"delay_queueName";var?routingkey?=?"delay.delay";var?argMaps?=?new?Dictionary<string,?object>(){{"x-delayed-type",?"topic"}};_channel.ExchangeDeclare(exchange:?exchangeName,?type:?"x-delayed-message",?true,?false,?argMaps);_channel.QueueDeclare(queueName,?true,?false,?false,?argMaps);_channel.QueueBind(queue:?queueName,?exchange:?exchangeName,?routingKey:?routingkey);//聲明為手動確認_channel.BasicQos(0,?1,?false);}protected?override?Task?ExecuteAsync(CancellationToken?stoppingToken){var?queueName?=?"delay_queueName";var?consumer?=?new?EventingBasicConsumer(_channel);consumer.Received?+=?(model,?ea)?=>{var?message?=?Encoding.UTF8.GetString(ea.Body.ToArray());var?routingKey?=?ea.RoutingKey;Console.WriteLine($"接受到消息的時間為?{DateTime.Now:yyyy-MM-dd?HH:mm:ss},routingKey:{routingKey}?message:{message}?");//手動確認_channel.BasicAck(ea.DeliveryTag,?true);};_channel.BasicConsume(queue:?queueName,?autoAck:?false,?consumer:?consumer);return?Task.CompletedTask;}public?override?void?Dispose(){_connection.Dispose();_channel.Dispose();base.Dispose();}
}

注冊該后臺任務

services.AddHostedService<RabbitmqDelayedHostService>();

輸出結果

成功發送消息:發送時間為 2022-07-02 18:54:22 延時時間為:5000

成功發送消息:發送時間為 2022-07-02 18:54:22 延時時間為:5000

成功發送消息:發送時間為 2022-07-02 18:54:22 延時時間為:5000

成功發送消息:發送時間為 2022-07-02 18:54:23 延時時間為:5000

成功發送消息:發送時間為 2022-07-02 18:54:23 延時時間為:5000

成功發送消息:發送時間為 2022-07-02 18:54:23 延時時間為:5000

接受到消息的時間為 2022-07-02 18:54:27,routingKey:delay.delay message:發送時間為 2022-07-02 18:54:22 延時時間為:5000

接受到消息的時間為 2022-07-02 18:54:27,routingKey:delay.delay message:發送時間為 2022-07-02 18:54:22 延時時間為:5000

接受到消息的時間為 2022-07-02 18:54:27,routingKey:delay.delay message:發送時間為 2022-07-02 18:54:22 延時時間為:5000

接受到消息的時間為 2022-07-02 18:54:28,routingKey:delay.delay message:發送時間為 2022-07-02 18:54:23 延時時間為:5000

接受到消息的時間為 2022-07-02 18:54:28,routingKey:delay.delay message:發送時間為 2022-07-02 18:54:23 延時時間為:5000

接受到消息的時間為 2022-07-02 18:54:28,routingKey:delay.delay message:發送時間為 2022-07-02 18:54:23 延時時間為:5000

其他方案

  • Hangfire延遲隊列

BackgroundJob.Schedule(()?=>?Console.WriteLine("Delayed!"),TimeSpan.FromDays(7));
  • 時間輪

  • Redisson DelayQueue

  • 計時管理器

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/285305.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/285305.shtml
英文地址,請注明出處:http://en.pswp.cn/news/285305.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C語言試題134之畫直線

??個人主頁:個人主頁 ??系列專欄:C語言試題200例 ??推薦一款模擬面試、刷題神器?? 點擊跳轉進入網站 ?作者簡介:大家好,我是碼莎拉蒂,CSDN博客專家(全站排名Top 50),阿里云博客專家、51CTO博客專家、華為云享專家 1、題目 題目:用 line 畫直線 2 、溫馨提示…

KeyMob應用開發者服務平臺幫助開發者推廣和盈利

為什么80%的碼農都做不了架構師&#xff1f;>>> 2014年10月&#xff0c;新版KeyMob移動廣告聚合平臺正式上線&#xff0c;登入KeyMob移動廣告聚合平臺即可看到聚合功能&#xff0c;目前新KeyMob整合了國內外多家主流的廣告平臺&#xff0c;實實在在的為應用開發者賺…

Android GIS開發系列-- 入門季(13)Gdal簡單寫個shp文件

Gdal是用來讀寫柵格與矢量數據的&#xff0c;在Gdal官網&#xff0c;可以下載相關的資源進行平臺的編譯。其實Arcgis底層也是用Gdal來讀取shp文件的&#xff0c;那在Android中可以直接讀寫shp文件嗎&#xff0c;是可以的。這里已經有人編譯了Android端的so &#xff0c;下載地址…

VS code 搭建Vue 項目

必備工具&#xff1a;Vs Code、NodeJs 1、新建一文件目錄來存放工程文件 2、右鍵用VS Code打開 3、Ctr 打開terminal面板&#xff0c;建議先將設置鏡像服務器&#xff0c;可能否則安裝比較慢。 npm config set registry https://registry.npm.taobao.org --globalnpm config…

C語言試題135之畫方形

??個人主頁:個人主頁 ??系列專欄:C語言試題200例 ??推薦一款模擬面試、刷題神器?? 點擊跳轉進入網站 ?作者簡介:大家好,我是碼莎拉蒂,CSDN博客專家(全站排名Top 50),阿里云博客專家、51CTO博客專家、華為云享專家 1、題目 題目:用 rectangle 畫方形 2 、溫…

C#(Sharp)操作數據庫原理及案例精析(強烈建議收藏)

劉一哥C#從入門到精通系列精品教程合集: 1.【C#程序設計】教學講義——第一章:C#語言概述 2.【C#程序設計】教學講義——第二章:簡單C#程序設計 3.【C#程序設計】教學講義——第三章:C#語言基礎 4.吐血整理:C#順序、選擇、循環結構用法與案例,這一篇就夠了! 5.C#數組原來…

SpringMVC4零配置--web.xml

servlet3.0規范后&#xff0c;允許servlet&#xff0c;filter&#xff0c;listener不必聲明在web.xml中&#xff0c;而是以硬編碼的方式存在&#xff0c;實現容器的零配置。 ServletContainerInitializer&#xff1a;啟動容器時負責加載相關配置 Java代碼 package javax.servl…

GoldenGate介紹

Oracle Golden Gate軟件是一種基于日志的結構化數據復制備份軟件&#xff0c;它通過解析源數據庫在線日志或歸檔日志獲得數據的增量變化&#xff0c;再將這些變化應用到目標數據庫&#xff0c;從而實現源數據庫與目標數據庫同步。Oracle Golden Gate可以在異構的IT基礎結構&…

[轉]我們為什么要用vue,他解決了什么問題,如何使用它?

Vue.js新手入門指南 最近在逛各大網站&#xff0c;論壇&#xff0c;以及像SegmentFault等編程問答社區&#xff0c;發現Vue.js異常火爆&#xff0c;重復性的提問和內容也很多&#xff0c;樓主自己也趁著這個大前端的熱潮&#xff0c;著手學習了一段時間的Vue.js&#xff0c;目前…

java反射機制續

http://www.cnblogs.com/fingerboy/p/5325261.html轉載于:https://www.cnblogs.com/yangmin-78819/p/5328869.html

測量人看過來:多種語言編寫的測量坐標反算神器附源碼(C#/VB)

坐標正算:【小程序】坐標正算神器V1.0(附源程序) 坐標反算一直是困擾測量人的一個問題,坐標反算是指已知兩點坐標,反求邊長和方位角。本文演示用C#和VB語言實現過程。 文章目錄 一、坐標反算原理1. 原理圖2. 計算公式3. 象限角4. 限角和坐標方位角的關系二、C#語言實現1. …

如何獲取GC(垃圾回收器)的STW(暫停)時間?

前言在現代的容器化和微服務應用中&#xff0c;因為分布式的環境和錯綜復雜的調用關系&#xff0c;APM&#xff08;Application Performance Monitoring 應用性能監控&#xff09;顯得尤為重要&#xff0c;它通過采集應用程序各種指標和請求鏈路&#xff0c;讓你知道系統當前的…

C語言試題136之打印出楊輝三角形(要求打印出 10 行如下圖)

??個人主頁:個人主頁 ??系列專欄:C語言試題200例 ??推薦一款模擬面試、刷題神器?? 點擊跳轉進入網站 ?作者簡介:大家好,我是碼莎拉蒂,CSDN博客專家(全站排名Top 50),阿里云博客專家、51CTO博客專家、華為云享專家 1、題目 題目:打印出楊輝三角形(要求打印…

C#控件綁定數據源方式

1:控件數據源綁定泛型Dictionary<string,string> 1):Dictionart<string,string> Dnew Dictionary(string,string);xxx.DataSourcenew BindingList<string>(D.values.ToList());2):Dictionary<string, string> D new Dictionary<string,string>;…

【ArcGIS風暴】ArcGIS矢量數據分層設色后導出或裁剪后顏色分類丟失完美解決辦法

在利用ArcGIS做土地利用現狀圖或者規劃圖時,事先費了好大勁把每個地類對應的圖斑進行了符號化(用不同的顏色表示),后來把符號化好的數據導出,并進行加載,發現顏色分類完全丟失了,同樣,在利用某個重點區域范圍裁剪后,顏色變成了單一的顏色。 符號化成果: 導出后加載矢…

如何使用Cmder替換cmd

一、cmder介紹 cmder是一款Windows環境下非常簡潔美觀易用的cmd替代者&#xff0c;它支持了大部分的Linux命令。支持ssh連接linux&#xff0c;使用起來非常方便。比起cmd、powershell、conEmu&#xff0c;其界面美觀簡潔&#xff0c;功能強大。 二、下載地址 地址&#xff1a…

C語言試題137之畫點

??個人主頁:個人主頁 ??系列專欄:C語言試題200例 ??推薦一款模擬面試、刷題神器?? 點擊跳轉進入網站 ?作者簡介:大家好,我是碼莎拉蒂,CSDN博客專家(全站排名Top 50),阿里云博客專家、51CTO博客專家、華為云享專家 1、題目 題目:利用putpixel 畫點。 2 、溫…

7z壓縮文檔的powershell示例

首先要安裝7-Zip到c:\Program Files\7-Zip&#xff1b; 示例如下&#xff1a; 1234567891011121314151617181920212223242526272829303132#define Function DeleteLogfunction DeleteLog{ param($filePath,$TimeOutDays) $allFilesget-childitem -path $filePath …

Delphi WinExec ShellExec 用法介紹

2019獨角獸企業重金招聘Python工程師標準>>> Delphi WinExec ShellExec 用法介紹 在Windows程序設計中WinAPI也為我們提供了類似的函數&#xff0c;它們就是WinExec()和ShellExecute()&#xff0c;下面就來討論一下這兩個函數的用法。 1)WinExec() 函數原型&#x…

各大主流編程語言性能PK,結果出乎意料

出品 | OSC開源社區&#xff08;ID&#xff1a;oschina2013&#xff09;“什么編程語言速度最快”&#xff0c;為了回答這個問題&#xff0c;The Benchmarks Game 專門面向主流編程語言設計了性能測試。測試的項目包括&#xff08;可點擊文末閱讀原文查看詳情&#xff09;&…