在我的api控制器中,我有一个名为“ SendMail”的方法,该方法接收带有JSON正文的帖子,如下所示:
{
"MailTo": "abcdefg@hijklmn.opqrst",
"Subject": "This is the subject",
"Body": "This is the body"
}
收到请求后,方法“ SendMail”将验证数据,如果正确,则发送邮件。
[HttpPost]
public IHttpActionResult SendMail([FromBody] MailData mailData)
{
if(ValidateMailData(mailData) == true)
{
Email.send(mailData);
return Ok("Your email was sent!");
}
return BadRequest("Some error");
}
问题是,发送邮件时,调用方只会收到api的响应(并且要花很长时间),但是我只想验证数据,将响应返回给调用方,然后再发送异步发送邮件(对于是否实际发送了邮件,对于调用方而言并不重要,并且如果正确验证了数据,则将发送邮件)。这段代码只是一个例子,但恰恰说明了我面临的问题。
答案 0 :(得分:2)
您应该将应用程序的Web层与实际的服务层分离。
通常通过使用队列来完成。
这个想法是,您有一个Web层,它的职责是让用户请求完成某项工作,在这种情况下,实际的工作是发送电子邮件。实施应用程序Web层的Web服务应公开用户可以调用的终结点,以请求发送电子邮件。 Web服务端点应根据取决于您要求的业务规则来验证用户请求的内容。
如果用户请求有效,则将请求放入专用队列中,然后返回202接受的状态码响应(注意,在回复之前,您不必发送电子邮件) HTTP请求,您只需确保已成功将用户请求加入队列。
如果,否则,根据您的验证规则,用户请求无效,您将返回422无法处理的实体状态代码,以便用户了解其请求无效。
与此同时,排队的请求由一个或多个工作人员服务处理,这些工作人员是独立的应用程序(它们与Web服务器完全分离),其职责是执行实际工作以发送电子邮件。
您可以决定对Web服务器和后端服务使用不同的技术,它们只需要就Web服务器排队和后端服务出队的消息格式达成共识。这样做的方法很多。
请注意,这种架构比仅具有Web服务要复杂一些,但是它具有许多优点。有一个明确的关注点分离,基础架构的每个部分都能很好地扩展,因为它只做一件事,并且系统的不同部分都没有争用任何共享资源(嗯,队列实际上是争用的,但是有非常好的技术可以帮助您以正确的方式实现队列,例如服务总线。
要注意的另一重要事项是,在Web服务层中使用异步代码并不是一种更快地回复单个用户的方法,而是一种对更好地扩展网络服务器本身。线程是重要的资源,网络服务器使用线程来回复传入的HTTP请求。执行IO任务时,切勿阻塞线程以使其空闲以等待IO任务完成。相反,您应该使用异步api,以便您的线程启动异步任务(例如,使新请求排队以发送电子邮件),并立即将其返回到线程池,以便可以将其用于答复另一个传入的消息。同时由操作系统执行IO操作时的HTTP请求(或做其他有用的事情)。
想想这个比喻(最初由Jon Skeet撰写)。想象一下,您在家,想吃披萨。您决定致电自己喜欢的餐厅并订购披萨(比喻,您是主厨,而在家中披萨是IO任务)。
您认为在比萨从餐厅旅行到您的家中,或者坐在门前等待比萨而在此期间什么也没做的时候,订购比萨然后进行其他有用的操作效率更高吗?好吧,如果您是网络服务器,那么您很忙,并且一定要确保在比萨饼到家旅行时您要做很多重要的事情(阅读服务传入的HTTP请求)。