Azure Web角色中的后台线程
可以通过WebRole.cs OnStart()方法运行线程,以便我们可以通过aspx页面访问它以执行后台工作? 我知道正确的做法是使用工人角色,但我希望尽可能降低运行成本。Azure Web角色中的后台线程
这个想法是创建一个线程,总是会运行并等待工作,例如,如果我想进行阻塞操作就像发送电子邮件我会使用线程给出SendEmail方法,是否有可能去做?如果是这样,你能否给我提供一些可以指引我正确方向的例子?
我会suggets一个解决方案,是从莱昂和大卫的解决方案不同:
- 大卫的解决方案是确定的,但不是弹性的。实例/进程在处理任务时脱机了什么?
- Leon的解决方案大多适用于预定作业,但发送电子邮件并不总是按计划安排的(也许您想在有人在您的应用程序中注册时发送电子邮件)。
的另一种选择,你应该看看使用的是Windows Azure存储队列(他们很便宜)在这种情况下:
- Web应用程序:将消息发送到队列(如“发送电子邮件to [email protected]')
- WebRole.cs:在启动实例时产生一个新线程,让它侦听来自该队列的消息。每当消息到达时,处理它。如果成功,则从队列中删除消息。
该解决方案有很多优点。 WebRole.cs运行在与Web应用程序不同的进程中,因此对请求线程没有影响。除此之外,如果发送邮件因任何原因失败,邮件将保留在队列中并在下次处理。如果应用程序或进程崩溃,这将确保您不会丢失任何要执行的任务。
下面是一个让你开始的例子。请注意,如果您希望生产准备就绪(重试策略,异常处理,退避轮询等),则需要改进此代码:
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.Diagnostics;
using Microsoft.WindowsAzure.ServiceRuntime;
using Microsoft.WindowsAzure.StorageClient;
using System.Threading.Tasks;
namespace MvcWebRole1
{
public class WebRole : RoleEntryPoint
{
public override bool OnStart()
{
Task.Factory.StartNew(InitializeQueueListener);
return base.OnStart();
}
private void InitializeQueueListener()
{
Microsoft.WindowsAzure.CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
{
configSetter(Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment.GetConfigurationSettingValue(configName));
});
var storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
var queueStorage = storageAccount.CreateCloudQueueClient();
var queue = queueStorage.GetQueueReference("myqueue");
queue.CreateIfNotExist();
while (true)
{
CloudQueueMessage msg = queue.GetMessage();
if (msg != null)
{
// DO SOMETHING HERE
queue.DeleteMessage(msg);
}
else
{
System.Threading.Thread.Sleep(1000);
}
}
}
}
}
似乎是更好的解决方案,我愿意执行的工作类型,无论如何,我打算让队列与内部应用程序“交谈”,所以它不会那么昂贵......您可以进一步详细了解“在启动实例时产生一个新的线程并让它监听来自该队列的消息”? **如果你可以给我一个例子,或者指向一个样例,它解释了在WebRole.cs **中启动一个监听线程所涉及的线程部分,那将是非常好的。谢谢 – ToinoBiclas
同意 - 队列非常有弹性。我的意图是指出创建线程的可行性(这并不总是显而易见的)。 –
@Sandrino让我知道如果这是内联与您的解决方案...在WebRole.OnStart()'新线程(新ThreadStart(ClassListeningToQueue.Method0)''创建一个线程'然后在Method0内写入一个无限循环或条件循环它只通过WebRole.OnStop()'while(true){try {CloudQueueMessage msg = queue.GetMessage(); if(msg!= null){''finnaly根据msg中的值执行任务,例如我可以有一个字段指出调用的方法和参数,在主线程中调用其他线程是否安全? – ToinoBiclas
我发现这个时候我一直在寻找的“蔚蓝计划任务”:http://www.ronaldwidha.net/2011/02/23/cron-job-on-azure-using-scheduled-task-on-a-web-role-to-replace-azure-worker-role-for-background-job/
看起来正是你要寻找的。
您指出的例子是用于运行预定作业,很像Linux中的crontabs。我愿意做一个等待被发信号的线程。 – ToinoBiclas
这只是指出,完全可以做这些事情。我想你可以用一点创意想出一个解决方案。 –
绝对可以创建一个线程(或很多)。 Web角色基本上是Windows 2008 Server。您不需要单独的工作人员角色来设置后台任务。当然,你的可以有一个单独的辅助角色,这将允许你扩展这些实例,而不依赖于你的Web角色实例。这是您需要平衡性能/扩展与成本之间的关系。
你能给我一些关于如何做到这一点的细节?如果我已经在WebRole:RoleEntryPoint中声明了,我怎样才能从一个aspx网页访问线程变量? – ToinoBiclas
如果您需要与aspx页面中的线程交互,为什么不从global.asax启动线程? RoleEntryPoint将在单独的AppDomain中运行,因此您不会在应用程序和线程之间进行交互。 –
老实说从未想过这件事。我将尝试使用global.asax中声明的线程池进行一些测试。 – ToinoBiclas
这将如何降低运行成本?你想要什么不同于单实例单一并发服务? – Paparazzi
@Blam - 在Web角色中运行后台任务允许将操作组合成一组VM实例。这与将背景操作放在单独的一组角色实例中形成鲜明对比。组合成一个角色将节省成本,因为每个角色必须至少有一个实例正在运行。对于小批量网站,这是一个非常节省成本的架构。如果存在背景任务挨饿网站的风险,或者需要分别缩放前端和后台任务(或者需要不同的VM大小),则值得考虑转向单独的角色。 –
@DavidMakogon谢谢我不知道一个工作者角色需要一个单独的实例。我没有试图回答这个问题。 +1我从这个问题中学到了很多东西。 – Paparazzi