Scene
There is a scenario, a mail alert for the Windows service that gets all the users who turn on mailtips, loops over the messages of those users, and sends a service number message. But the problem comes, the user is less than the case, polling time can endure, if the user is more, the user name sorted by the people, receive email reminders message, delay time is very long.
Get ready
C # Redis Practice list,hashtable
Redis Queue of C #
Scheme
1, the producer thread one gets all the users who open the email alert.
2, according to the configuration to determine the number of queues to use, and the capacity of each queue.
3, line Cheng, get the queue is not full, the current user is enqueued. If all the queues are full, suspend 2s, and then regain the queue that is not full, and the user is queued.
4, according to the configuration to open the consumer thread, each thread independent processing logic. Suspends 2s if the obtained user is empty or the current queue is empty. Otherwise, the user's message is pulled through the EWS service, and a reminder is taken.
5. If an error occurs during the acquisition of a user's message, the user is re-entered into the current queue, waiting for the next pull.
Test
Queue
Test code
///<summary>///Message Queuing Management///</summary>PublicClassmyredisqueuebus:idisposable {///<summary>///Number of threads///</summary>PrivateInt_threadcount;///<summary>///The capacity of Itcode in each thread///</summary>PrivateInt_threadcapacity;///<summary>///Thread///</summary>PrivateThread[] _threads;///<summary>///Producer Threads///</summary>PrivateThread _producerthread;///<summary>///Suspend time///</summary>PrivateConstint Waitseconde =2000;///<summary>///Queue name Prefix///</summary>PrivateString_queueprefix;///<summary>///constructor function///</summary>///<param name= "ThreadCount" >Number of threads</param>///<param name= "Threadcapacity" >Queue capacity processed per thread</param>///<param name= "Queueprefix" >Queue capacity processed per thread</param>Public Myredisqueuebus (int ThreadCount,int threadcapacity,StringQueueprefix) {This._threadcapacity =threadcapacity;This._threadcount =ThreadCount;This._queueprefix = Queueprefix +"_{0}"; }///<summary>///Open producer///</summary>PublicvoidStartproducer () {_producerthread =New Thread (() ={Iredisclientfactory factory =Redisclientfactory.instance; Emailalertsdata Emailalertsdata =NewEmailalertsdata ();//White Liststring[] Useridswhitearray = TaskGloableParameter.WhiteList.Split (NewChar[] {‘,‘,‘,‘}, Stringsplitoptions.removeemptyentries);//Teamusing (iredisclient client =Factory. Createredisclient (Webconfig.redisserver, Webconfig.redisport)) {client. Password =Webconfig.redispwd; Client. Db =Webconfig.redisserverdb;while (True) {//Get all the users who turned on the email alert list<emailalerts> lstemails =Emailalertsdata.getallstartalerts (Syncstate.all, Useridswhitearray);foreach (VAR itemInchLstemails) {int Queueindex =-1;String queuename =String. Format (This. _queueprefix, Queueindex);for (int i =0; i < _threadcount; i++) {QueueName =String. Format (This. _queueprefix, I);//If the current queue is not filled, jump out and use the queue to Enqueueif (client. GetListCount (QueueName) <_threadcapacity) {Queueindex =IBreak; } }//If all the queues are full, suspend 2s wait for the consumer to consume a portion of the data and start over againif (Queueindex = =-1) {thread.spinwait (Waitseconde);//Re-fetch queuefor (int i =0; i < _threadcount; i++) {QueueName =String. Format (This. _queueprefix, I);//If the current queue is not filled, jump out and use the queue to Enqueueif (client. GetListCount (QueueName) <_threadcapacity) {Queueindex =IBreak; } } }Else{//The queue client. Enqueueitemonlist (QueueName, Jsonconvert.serializeobject (NewMyqueueitem {UserId =Item.itcode, syncstate =Item. Email_syncstate})); } } } } }); _producerthread.start (); }///<summary>///Open Consumer///</summary>PublicvoidStartcustomer () {_threads =New Thread[_threadcount]; for (int i = 0; i < _threads. Length; i++) {_threads[i] = new Thread (customerrun); _threads[i]. Start (i); }} private void Customerrun (object obj) {int threadindex = Convert.ToInt32 (obj); string queuename = String. Format (This._queueprefix, Threadindex); Iredisclientfactory factory = redisclientfactory.instance; using (iredisclient client = factory. Createredisclient (Webconfig.redisserver, Webconfig.redisport)) {while (true) {client. Password = webconfig.redispwd; Client. Db = Webconfig.redisserverdb; if (client. GetListCount (QueueName) > 0) {string Resultjson = client. Dequeueitemfromlist (QueueName); If the obtained result is empty, the 2s if (string) is suspended. IsNullOrEmpty (Resultjson)) {thread.spinwait (Waitseconde);} else {try {//time consuming business processing Myqueueitem item = jsonconvert.deserial Izeobject<myqueueitem> (Resultjson); Console.WriteLine ("Threadid:{0},user:{1}", Thread.CurrentThread.ManagedThreadId.ToString (), item. USERID); } catch (Exception ex) {//If an error occurs, re-queue the client. Enqueueitemonlist (qUeuename, Resultjson); }}} else {//The current queue is empty, pending 2s thread.spinwait (Waitseconde);}} }} public void Dispose () {//release resource, Destroy thread if (this._threads! = null) {for (int i = 0; i < this._threads. Length; i++) {This._threads[i]. Abort (); }} GC. Collect (); } }
Main method call
void Main (string[] args) { new Myredisqueuebus ("mail_reminder_queue"); Bus. Startproducer (); Thread.spinwait (a); bus. Startcustomer (); Console.read (); }
Summarize
By configuration, determine the number of open queues and the number of threads, if the user increases can increase the number of threads, or add a machine to resolve. In this way, you can solve the post-ranked users, through the random distribution queue, have the opportunity to get email reminders in advance, you can shorten the delay time of email reminders. Of course, such a scheme is not perfect, and can only be thought of here now. This idea is written here, and it is hoped to get a better solution.
The above code is just the code for testing, and later found to create iredisclient written in the loop, very prone to problems, frequent creation of the client, also thought that this frequent turn off, if not released, then will produce a lot of redis connection, resulting in the Redis server burden. If placed outside the loop, the client is responsible for fetching data from the queue until the thread stops.
Reprint: Blog Address: http://www.cnblogs.com/wolf-sun/
Application of Redis queue in C # to email alerts