Отсылка электронных писем из Windows Azure приложений

| Воскресенье, 16 июня, 2013

Метки: ASP.NET MVC, Windows Azure Комментарии: 0

Использовать worker-роль внутри web-роли для малого трафика дешевле

Изучая Windows Azure, разработчики наверняка знают, что такое worker-роли и зачем они нужны. Это виртуальные машины, предназначенные для выполнения фоновых вычислений. Но есть небольшая проблема в их использовании в самом начале запуска проекта. Если у приложения небольшое количество пользователей и нагрузка в виде фоновых вычислений низкая, то worker-роль использовать достаточно накладно и излишне. Для чего резервировать целый сервер для редкой и несложной работы? Поэтому использовать уже имеющуюся web-роль, в которой работает само веб-приложение будет разумным решением в самом начале, пока вы не набрали большое количество пользователей.

Worker-роль состоит из класса, который наследуется от RoleEntryPoint. Это выглядит примерно так:

public class WorkerRole : RoleEntryPoint
{
    public override bool OnStart()
    {
        // ...
 
        return base.OnStart();
    }
 
    public override void Run()
    {
        while (true)
        {
            // ...
        }
    }
}

Этот же самый код будет работать и в web-роли. Просто добавим этот класс в проект ASP.NET MVC и эта роль будет работать как worker-роль, находясь в виртуальной машине web-роли.

На первых порах это решение поможет сократить ненужные траты, но как только нагрузка на приложение будет возрастать, то класс роли можно перенести в приложение worker-роли и масштабировать приложение по мере его роста.

Отсылка email-сообщений

На данный момент мы имеем зависшее сообщение в очереди и мы знаем как понизить расходы используя worker-роль внутри web-роли. Давайте теперь отправим email. Будем использовать сервис SendGrid, который предоставляет преимущество быстрой разработки. Установим эту библиотеку через Nuget.

После установки библиотеки SendGrid можно написать код, который читает сообщения из очереди и отправляет письма. Ниже код чтения из очереди:

public class WebRole : RoleEntryPoint
{
    public override bool OnStart()
    {
        CloudStorageAccount.SetConfigurationSettingPublisher(
              (configName, configSetter) =>
        {
            string value = "";
            if (RoleEnvironment.IsAvailable)
            {
                value = RoleEnvironment.
                       GetConfigurationSettingValue(configName);
            }
            else
            {
                value = ConfigurationManager.AppSettings[configName];
            }
 
            configSetter(value);
        });
 
        return base.OnStart();
    }
 
    public override void Run()
    {
        // emailconfirmation очередь
        var account = CloudStorageAccount.
                      FromConfigurationSetting("StorageConnection");
        var queueClient = account.CreateCloudQueueClient();
        var queue = queueClient.GetQueueReference("emailconfirmation");
        queue.CreateIfNotExist();
 
        while (true)
        {
            var message = queue.GetMessage();
            if (message != null)
            {
                // ...
 
                // отметим, что сообщение обработано
                queue.DeleteMessage(message);
            }
            else
            {
                Thread.Sleep(TimeSpan.FromSeconds(30));
            }
        }
    }
}

Как можно видеть из кода, чтение из очереди довольно прямолинейно. Аккаунт хранилища используется для получения ссылки на очередь. И дальше идет бесконечный цикл, забирающий сообщения из очереди. Если сообщение получено, то оно обрабатывается, а если очередь пуста, то происходит пауза на 30 секунд, и потом опять происходит попытка чтения сообщения из очереди.

После прочтения сообщения, десериализуем его, и затем отправляем email через SendGrid:

// десериализуем модель
var serializer = new JavaScriptSerializer();
var model = serializer.Deserialize(message.AsString);
 
// создаем новый email объект, используя SendGrid
var email = SendGrid.GenerateInstance();
email.From = new MailAddress("service@codehint.ru", "Codehint.ru");
email.AddTo(model.Email);
email.Subject = "Добро пожаловать на сайт Codehint.ru!";
email.Html = string.Format(
    "

Привет {0},

" + "

Добро пожаловать на сайт Codehint.ru!

" + "

С наилучшими пожеланиями,
Codehint.Ru

", model.Name); var transportInstance = REST.GetInstance( new NetworkCredential("username", "password")); transportInstance.Deliver(email); // отмечаем, что сообщение обработано queue.DeleteMessage(message);

Одна вещь, которую нужно отметить. Удаляем сообщение из очереди только после того, как оно успешно обработано. Если, например, worker-роль по каким либо причинам выйдет из строя, то сообщение будет оставаться в очереди и обработается новой worker-ролью. Такой способ не дает пропасть сообщениям и дает гарантию, что они будут обработаны.

Комментарии
Никто еще не оставил здесь комментарий.
Войдите, чтобы написать комментарий , или воспользуйтесь формой ниже.
 

Copyright © CodeHint.ru 2013-2019