iT邦幫忙

DAY 27
10

使用Asp.Net MVC打造Web Api系列 第 27

使用Asp.Net MVC打造Web Api (27) - 在Azure上執行排程工作

我們在營運線上網站時,除了網站本身的維護之外,也常常會遇到需求是必須定期執行一些批次程式,有可能是用來更新靜態檔案讓資料保持在最新版本,又或是檢查系統資料是否有異常的情況發生,若有異常情況就馬上發送警告通知讓維護人員知道,而今天的內容就是要向大家介紹如何在Azure上設定排程工作並執行。
※使用Windows的Task Scheduler進行排程工作
Azure的Cloud Service其實也是由一個個的VM所構成,而VM中當然會具有Windows的Task Scheduler,因此我們可以透過一些簡單的Command,讓Cloud Service在發行時新增一個排程工作,這麼一來就可以最快速的實現我們想要的排程功能,這也是所需成本最低的一種方法!

  1. 新增一個批次工作內容

        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);
            }
        }
    
  2. 建立成批次

        public class Program
        {
            static void Main(string[] args)
            {
                BatchJob job = new BatchJob();
                job.Execute();
    
                Console.WriteLine("Finish!");
                Console.Read();
            }
        }
    
  3. 將批次放到WebRole的專案中,並設置為複製到輸出目錄

  4. 新增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所在目錄
5. 修改發行專案的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>   
  1. 發行網站就完成了批次工作的建立

延伸閱讀:

* CRON job on Azure: Using Scheduled Task on a Web Role to replace Azure Worker Role for background job

※使用Worker Role配合Schedule Library撰寫排程工作
除了使用VM中的Task Scheduler之外,我們也可以建立一個Worker Role,並且利用Schedule的Library執行Job的方式來執行排程工作

  1. 新增Cloud Service專案

  2. 新增一個背景工作角色

  3. 使用Nuget加入Quartz.Net Library

  4. 新增一個批次的邏輯

        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);
            }
        }
    
  5. 在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();
            }
        }
    
  6. 發行背景工作角色到雲端,完成排程批次的設定!

延伸閱讀:
* Cron format
* Quartz.Net

※使用MobileService和Service Bus Queue來執行批次工作

  1. 在Service Bus新增一個服務,並取得金鑰

  2. 建立一個行動服務,並且選擇排程器

  3. 建立一個排程工作

  4. 輸入指令碼,透過排程器,時間到時新增一個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);
                }
            });
        }
    
  5. 執行一次後,可以看到確實新增了資料到佇列中

  6. 我們只要建立一個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();
            }
        }
    
  7. 開啟MobileService排程以及發行批次執行的Worker Role即可

延伸閱讀:
* Azure Task Scheduling Options

※本日小結
透過一些簡單的排程工作,可以減低平常我們在維運網站時的手工作業,更甚至可以藉由一些定時的資料檢查來確認系統有沒有異常的狀況,今天主要也是提供一些在Azure上設立排程工作的方法給大家,大家可以依據自己的使用情境選擇適合的來使用,關於今天的內容,歡迎大家一起討論 ^_^


上一篇
使用Asp.Net MVC打造Web Api (26) - 使用Azure Service Bus處理瞬間大量請求
下一篇
使用Asp.Net MVC打造Web Api (28) - 管理網站錯誤資料
系列文
使用Asp.Net MVC打造Web Api30

2 則留言

0

我要留言

立即登入留言