我們在營運線上網站時,除了網站本身的維護之外,也常常會遇到需求是必須定期執行一些批次程式,有可能是用來更新靜態檔案讓資料保持在最新版本,又或是檢查系統資料是否有異常的情況發生,若有異常情況就馬上發送警告通知讓維護人員知道,而今天的內容就是要向大家介紹如何在Azure上設定排程工作並執行。
使用Windows的Task Scheduler進行排程工作
Azure的Cloud Service其實也是由一個個的VM所構成,而VM中當然會具有Windows的Task Scheduler,因此我們可以透過一些簡單的Command,讓Cloud Service在發行時新增一個排程工作,這麼一來就可以最快速的實現我們想要的排程功能,這也是所需成本最低的一種方法!
-
新增一個批次工作內容
public class BatchJob { public void Execute() { MailAddress from = new MailAddress("xxx@gmail.com", "kirkchen", Encoding.UTF8); MailMessage mail = new MailMessage(from, new MailAddress("xxx@gmail.com")); string subject = "Test Subject"; mail.Subject = subject; mail.SubjectEncoding = Encoding.UTF8; string body = "Test Body"; mail.Body = body; mail.BodyEncoding = Encoding.UTF8; mail.IsBodyHtml = false; mail.Priority = MailPriority.High; SmtpClient client = new SmtpClient(); client.Host = "smtp.gmail.com"; client.Port = 587; client.Credentials = new NetworkCredential("xxx", "xxx"); client.EnableSsl = true; client.Send(mail); } }
-
建立成批次
public class Program { static void Main(string[] args) { BatchJob job = new BatchJob(); job.Execute(); Console.WriteLine("Finish!"); Console.Read(); } }
-
將批次放到WebRole的專案中,並設置為複製到輸出目錄
-
新增cmd檔,建立排程工作
::Start Task Scheduler Service net start "task scheduler" ::Create user for schedule job net user jobuser1 P@ssw0rd /add ::Set user as adimn net localgroup Administrators jobuser1 /add ::Create Schedule job schtasks /create /SC MINUTE /MO 1 /TN BatchJob /TR %~dp0BatchJob/ApiSample.Consoles.Console.exe /F /RU jobuser1 /RP P@ssw0rd
註: %~dp0可以取得cmd所在目錄
-
修改發行專案的ServiceDefinition.csdef(或*.csdef),在發行時啟動cmd檔
<WebRole name="ApiSample.UI.WebSite" vmsize="ExtraSmall"> <Sites> <Site name="Web"> <Bindings> <Binding name="Endpoint1" endpointName="Endpoint1" /> </Bindings> </Site> </Sites> <Startup> <Task commandLine="Batchs\startuptask.cmd" executionContext="elevated" taskType="simple" /> </Startup> <Endpoints> <InputEndpoint name="Endpoint1" protocol="http" port="80" /> </Endpoints> <Imports> <Import moduleName="Diagnostics" /> <Import moduleName="RemoteAccess" /> <Import moduleName="RemoteForwarder" /> </Imports> </WebRole>
發行網站就完成了批次工作的建立
延伸閱讀:
使用Worker Role配合Schedule Library撰寫排程工作
除了使用VM中的Task Scheduler之外,我們也可以建立一個Worker Role,並且利用Schedule的Library執行Job的方式來執行排程工作
-
新增Cloud Service專案
-
新增一個背景工作角色
-
使用Nuget加入Quartz.Net Library
-
新增一個批次的邏輯
public class BatchJob : IJob { public void Execute(IJobExecutionContext context) { Trace.Write("Execute Job"); MailAddress from = new MailAddress("xxx@gmail.com", "kirkchen", Encoding.UTF8); MailMessage mail = new MailMessage(from, new MailAddress("xxx@gmail.com")); string subject = "Test Subject"; mail.Subject = subject; mail.SubjectEncoding = Encoding.UTF8; string body = "Test Body"; mail.Body = body; mail.BodyEncoding = Encoding.UTF8; mail.IsBodyHtml = false; mail.Priority = MailPriority.High; SmtpClient client = new SmtpClient(); client.Host = "smtp.gmail.com"; client.Port = 587; client.Credentials = new NetworkCredential("xxx", "xxx"); client.EnableSsl = true; client.Send(mail); } }
-
在Worker Role使用Quartz.Net設定批次的排程
public class WorkerRole : RoleEntryPoint { private IScheduler scheduler; private ManualResetEvent CompletedEvent = new ManualResetEvent(false); public override void Run() { DateTimeOffset runTime = DateBuilder.EvenMinuteDate(DateTime.UtcNow); DateTimeOffset startTime = DateBuilder.NextGivenSecondDate(null, 10); var job = JobBuilder.Create<BatchJob>() .WithIdentity("BatchJob", null) .Build(); ITrigger trigger = TriggerBuilder.Create() .WithIdentity("default", null) .StartAt(runTime) // execute preiod with cron format .WithCronSchedule("1 * * * * ?") .Build(); scheduler.ScheduleJob(job, trigger); this.CompletedEvent.WaitOne(); } public override bool OnStart() { // construct a scheduler factory ISchedulerFactory factory = new StdSchedulerFactory(); // get a scheduler this.scheduler = factory.GetScheduler(); this.scheduler.Start(); return base.OnStart(); } public override void OnStop() { this.scheduler.Clear(); this.CompletedEvent.Set(); base.OnStop(); } }
發行背景工作角色到雲端,完成排程批次的設定!
延伸閱讀:
使用MobileService和Service Bus Queue來執行批次工作
-
在Service Bus新增一個服務,並取得金鑰
-
建立一個行動服務,並且選擇排程器
-
建立一個排程工作
-
輸入指令碼,透過排程器,時間到時新增一個Queue Message
function BatchJob() { var azure = require('azure'); console.info('Start TestService Bus'); var queueService = azure.createServiceBusService('[servicebus name]','[servicebus key'); queueService.createQueueIfNotExists('job', function(error){ if(!error){ console.info(error); } }); var message = { body: 'BatchJob' }; queueService.sendQueueMessage('job', message, function(error){ if(!error){ console.info(error); } }); }
-
執行一次後,可以看到確實新增了資料到佇列中
-
我們只要建立一個Worker Role,在有訊息佇列時執行工作即可
public class WorkerRole : RoleEntryPoint { // 佇列的名稱 const string QueueName = "job"; // QueueClient 可進行安全對話。已建議您進行快取, // 而非在每次要求時重新建立 QueueClient Client; ManualResetEvent CompletedEvent = new ManualResetEvent(false); public override void Run() { Trace.WriteLine("開始處理訊息"); // 起始訊息幫浦,且已叫用每則已收到的訊息回呼,用戶端結果的呼叫會停止幫浦。 Client.OnMessage((receivedMessage) => { try { var message = receivedMessage.GetBody<string>(); if(message!="BatchJob"){ return; } MailAddress from = new MailAddress("xxx@gmail.com", "kirkchen", Encoding.UTF8); MailMessage mail = new MailMessage(from, new MailAddress("xxx@gmail.com")); string subject = "Test Subject"; mail.Subject = subject; mail.SubjectEncoding = Encoding.UTF8; string body = "Test Body"; mail.Body = body; mail.BodyEncoding = Encoding.UTF8; mail.IsBodyHtml = false; mail.Priority = MailPriority.High; SmtpClient client = new SmtpClient(); client.Host = "smtp.gmail.com"; client.Port = 587; client.Credentials = new NetworkCredential("xxx", "xxx"); client.EnableSsl = true; client.Send(mail); receivedMessage.Complete(); } catch { receivedMessage.Abandon(); } }); CompletedEvent.WaitOne(); } public override bool OnStart() { // 設定並行連線數目上限 ServicePointManager.DefaultConnectionLimit = 12; // 若不存在,請建立佇列 string connectionString = CloudConfigurationManager.GetSetting("Microsoft.ServiceBus.ConnectionString"); var namespaceManager = NamespaceManager.CreateFromConnectionString(connectionString); if (!namespaceManager.QueueExists(QueueName)) { namespaceManager.CreateQueue(QueueName); } // 起始到 Service Bus 佇列的連線 Client = QueueClient.CreateFromConnectionString(connectionString, QueueName); return base.OnStart(); } public override void OnStop() { // 關閉到 Service Bus 佇列的連線 Client.Close(); CompletedEvent.Set(); base.OnStop(); } }
開啟MobileService排程以及發行批次執行的Worker Role即可
延伸閱讀:
本日小結
透過一些簡單的排程工作,可以減低平常我們在維運網站時的手工作業,更甚至可以藉由一些定時的資料檢查來確認系統有沒有異常的狀況,今天主要也是提供一些在Azure上設立排程工作的方法給大家,大家可以依據自己的使用情境選擇適合的來使用,關於今天的內容,歡迎大家一起討論 ^_^