对于实现线程化电子邮件发送队列的类,设计是什么样的? [英] What would the design look like for a class that implements a threaded email sending queue?

查看:86
本文介绍了对于实现线程化电子邮件发送队列的类,设计是什么样的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

因此,我的应用程序是出租车呼叫调度系统,其中操作员通过电话接收呼叫,并将接收到的呼叫分配给驾驶员.在输入呼叫详细信息的呼叫详细信息"表单上,一旦单击保存"按钮,该表单应关闭,应在后台线程中向出租车司机发送电子邮件,并显示主表单,在该表单中他可以选择下一个呼叫并将其分配给另一个驱动程序.

关于设计的难题是它应该是一个队列,这意味着队列中的电子邮件需要等待,直到对发送的电子邮件的处理完成为止.当然,电子邮件发送发生在与VCL主线程不同的线程中.

返回主线程的唯一响应是,通过从主线程到电子邮件程序线程的函数调用,队列中剩余要发送的电子邮件数量.例如.如果用户尝试关闭该应用程序,它将询问电子邮件程序队列类,队列中是否有任何待处理的电子邮件.

在Delphi中,哪种类设计和构造将最好地实现此功能?我确定它具有一个或多个TThreads,但是我已经迷失了.我本可以开始写一些东西,但是我确定那是错的,我需要将其拆开,在此处发布,然后根据建议重新开始.这就是为什么我首先在​​这里发布-我想要设计提示.由于我使用的是Delphi,因此在这里发布是因为我想要特定于Delphi的设计技巧.预先感谢您提供任何答案.

注意:我愿意使用TThread实现或OmniThreadLibrary.

我为该类提供了一个基本模板,答案将需要在此模板上扩展和构建.

unit uEmailQueue;

interface

uses Classes;

type
  TEmailServer = record
    SMTPHost: String;
    SMTPPort: Integer;
    SMTPUseSSL: Boolean;
    SMTPUserName: String;
    SMTPPassword: String;
    SMTPSenderName: String;
  end;

  TEmailMessage = record
    RecipientEmailAddr: String;
    EmailSubject: String;
    EmailMessage: String;
  end;

  TEmailQueue = class(TObject)
  private
    FEmailServer: TEmailServer;
  public
    procedure SendEmail(AEmailMessage: TEmailMessage);
  end;

implementation

{ TEmailQueue }

procedure TEmailQueue.SendEmail(AEmailMessage: TEmailMessage);
begin

end;

end.

解决方案

我建议您设置OTL.

您很可能拥有唯一的SMTP服务器,因此也只有唯一的邮件发送线程,以防日后要添加更多的通知发送服务器(例如向不同的电话运营商发送SMS的消息)–您将添加更多的传出接收器"线程

我个人会考虑使用管道模式.

目前看来,它似乎主要是过度设计,但稍后会为您提供自定义和扩展功能(例如,添加更多的通知方式而不是发送电子邮件,例如记录过程,例如添加"VIP客户端/常规客户端/阴暗的客户/欺诈"启发式)或其他任何内容.

由于管道始于一些线程安全的源数据收集/容器,因此要开始处理新请求,只需要将任务记录放入该队列中.

类似

 var TaxiInQueue: iOmniBlockingCollection;
 ....
 var NewTask: TEmailMessage;
 ...
 TaxiInQueue.Add( TOmniValue.FromRecord(NewTask) );

同样,这将为您提供扩展,使单线程GUI应用程序(通过单个代理放置新任务)扩展到网络代理(3层或WWW-servlet),并通过多个线程从不同的连接中同时输入新任务/threads.

返回主线程的唯一响应是队列中剩余要发送的电子邮件数量

我个人将以双重核算"的方式进行,我将保留两个变量:已创建的任务总数和已完成的任务总数.可以通过主线程中一个单独的不可见窗口(AllocateHWND并使用PostMessage触发增量)来管理它们,也可以通过一个单独的工作线程(可能是过度工程)来管理它们,也可以通过其中带有任何类型的MREW锁的某个对象来对其进行管理. /p>

增量将是当前(或稍微过时)的队列长度.而且,windows/thread/object能够生成自己的事件(例如,如果队列空闲,正常或溢出,则绘制一些仪表)

关于MREW锁,在Delphi RTL中有一个存货,在OTL库中还有一个存货,还有一个人将OmniMREW移植到Lzarus,然后制造了另一个他认为更有效的锁. /p>

So my application is a taxi call dispatch system, in which an operator receives calls over the phone and assigns received calls to a driver. On the Call Details form where the call detail is entered, as soon as the Save button is clicked, the form should close, should send an email to the taxi cab driver in a background thread, and the main form is shown, where he can select the next call and assign it to another driver.

The hard bit about the design is that it should be a queue, meaning an email in the queue needs to wait until processing for an email that is being sent has completed. Of course the email sending is happening in a different thread than the main VCL thread.

There only response back to the main thread would be the number of emails remaining to be sent in the queue, via a function call from the main thread to the emailer thread. Eg. if the user tries to close the application, it will ask the emailer queue class if there are any emails pending in the queue.

In Delphi, what class design and constructs will best implement this functionality? I'm sure it has one or more TThreads, but I'm lost beyond that. I could have started writing something, but I'm sure it would have been wrong, and I would need to tear it apart, post here and start again based on recommendations. That is why I posted here first - I want design tips. Since I'm using Delphi, I posted here because I want Delphi-specific design tips. Thanks in advance for any answers.

Note: I'm open to using either a TThread implementation or OmniThreadLibrary.

I'm including a basic template for the class, which the answer will need to expand and build upon.

unit uEmailQueue;

interface

uses Classes;

type
  TEmailServer = record
    SMTPHost: String;
    SMTPPort: Integer;
    SMTPUseSSL: Boolean;
    SMTPUserName: String;
    SMTPPassword: String;
    SMTPSenderName: String;
  end;

  TEmailMessage = record
    RecipientEmailAddr: String;
    EmailSubject: String;
    EmailMessage: String;
  end;

  TEmailQueue = class(TObject)
  private
    FEmailServer: TEmailServer;
  public
    procedure SendEmail(AEmailMessage: TEmailMessage);
  end;

implementation

{ TEmailQueue }

procedure TEmailQueue.SendEmail(AEmailMessage: TEmailMessage);
begin

end;

end.

解决方案

I suggest you to set up OTL.

You would most probably have the only SMTP server, so the only mail-sending thread, in case you would later add more notification sending servers ( like sending SMSes to different phone operators ) - you would add more outgoing "sink" threads.

Personally I would think about using the Pipeline pattern.

For now it looks mostly an over-engineering, but it would later provide you for customisations and extensions (like adding more notification means than sending e-mail, like logging of the process, like adding "VIP client/regular client/shady client/fraud" heuristics) or anything else.

Since the Pipeline starts with some thread-safe source data collection/container, to start the processing of the new request you would only need to put the task record into that queue.

Something like

 var TaxiInQueue: iOmniBlockingCollection;
 ....
 var NewTask: TEmailMessage;
 ...
 TaxiInQueue.Add( TOmniValue.FromRecord(NewTask) );

Again, that would provide you to extend from single-thread GUI application (with a single agent putting in new tasks) to a network agent (3-tier or WWW-servlet) with several threads inputting new tasks simultaneously from different connections/threads.

There only response back to the main thread would be the number of emails remaining to be sent in the queue

Personally I would do it in a "double accounting" way, i would keep two variables: total tasks created and total tasks finished. They can be managed by a separate invisible window in the main thread (AllocateHWND and using PostMessage to trigger increments), or a separate worker thread (over-engineering probably), or just some object with any kind of MREW-lock in it.

The delta would be the current (or slightly outdated) queue length. Also that windows/thread/object would be able to generate events of his own (like painting some meters if the queue is idle, normal, or overflowing)

Regarding MREW locks, there is a stock one in Delphi RTL, there is another one in OTL library itself, and there was some guy who ported OmniMREW to Lzarus, and then made another lock that he claims is even more efficient.

这篇关于对于实现线程化电子邮件发送队列的类,设计是什么样的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆