Микросервис Newsletter с использованием .NetCore, RedisJSON и Azure

Введение

В этой статье вы создадите сервис рассылки новостей на основе архитектуры микросервисов с использованием RedisJSON, .NET Core и Azure.
Вы будете использовать RedisJSON в качестве хранилища для хранения данных, связанных с подписками. RedisJSON — это высокопроизводительное хранилище документов NoSQL, предоставляемое компанией Redis.
Вы будете создавать REST Api с использованием .NET Core, который обеспечит CRUD-операции по управлению подписками и созданию рассылки для подписавшихся пользователей.
Вы также создадите бессерверную функцию с использованием Azure для обработки рассылки и отправки ее всем пользователям с помощью почтового сервиса SendGrid. Это будет полное практическое руководство.

Предварительные условия

  1. Вы будете использовать библиотеку Redis OM .NET для работы с документами в Redis. Для этого вы будете использовать .NET Core 6.
  2. IDE для написания .NET-кода. Visual Studio, VS Code или Rider, подойдет любая из них.
  3. Учетная запись Azure для Storage Queue и SendGrid для отправки электронной почты. Вы можете создать бесплатную учетную запись Azure здесь.
  4. Основные инструменты Azure Functions

Проектирование микросервиса рассылки новостей

В этой статье вы разработаете микросервис Newsletter, который позволит пользователям подписываться или отписываться от рассылки и позволит владельцу рассылки отправлять электронное письмо, когда он захочет.
Вы создадите REST API, который будет предоставлять операции подписки/отписки от рассылки, а также отправку рассылки. Для отправки рассылки вы создадите асинхронную операцию, в которой вы будете сохранять информацию о рассылке в очереди (очередь хранилища Azure) и создадите обработчик рассылки, который будет выбирать элементы рассылки из очереди, а затем отправлять электронное письмо подписавшимся пользователям с помощью SendGrid.
Здесь наиболее важным моментом являются сущности. Вам нужно создать несколько сущностей для хранения данных, связанных с подпиской и рассылкой.
Ниже приведена сущность Subscription, которая будет служить нам для хранения данных, связанных с подписками, в Redis.

string Id
string Email
DateTime SubscribedOn
bool IsSubscribed

Вход в полноэкранный режим Выход из полноэкранного режима

Ниже приведена сущность Newsletter, которая будет служить нам для хранения данных, связанных с рассылкой, и будет ставиться в очередь, когда пользователь попросит создать рассылку. Вы не будете хранить эту информацию, так как она нужна только для отправки писем (для упрощения дизайна).

List<string> Emails
string Subject
string Body

Вход в полноэкранный режим Выход из полноэкранного режима

После проектирования сущности вы создадите 3 конечные точки REST для подписки, отмены подписки на рассылку и отправки рассылки. После этого вы создадите функцию Azure для обработки рассылки, т.е. для отправки электронного письма.
В следующих разделах вы подробно рассмотрите все шаги. Давайте погрузимся 🙂

Настройка кластера Redis

Зарегистрируйтесь в облаке Redis по этой ссылке. Они предоставляют 200$ бесплатных кредитов для старта с помощью кода купона TIGER200.
Как только вы зарегистрируетесь и войдете в систему. Когда вы зарегистрируетесь, вам будет предложено выбрать облачного провайдера из Azure, google cloud, aws. Выберите любого из них, который вам больше нравится, после чего для вас будет создана бесплатная подписка.
Как только подписка будет создана, для вас также будет создана база данных, которая имеет модули RedisJSON, Redis Search, Redis Bloom, Redis Graph и Redis TimeSeries. Для нашего приложения вам нужны только Redis JSON и Redis Search. Поэтому вы удалите существующую базу данных и создадите новую.
Для удаления нажмите на базы данных в левой части опций в разделе Подписки. Вы увидите базу данных по умолчанию, которая создана для вас. После этого нажмите на имя базы данных, и вы попадете на страницу конфигурации базы данных. Прокрутите страницу вниз, и вы увидите опцию удаления в разделе «Опасная зона» в самом низу.

После этого вам нужно создать новую базу данных. Для этого снова нажмите на Опции подписки. Теперь под вашей подпиской нет базы данных, и у вас появится кнопка New Database для создания базы данных. Нажмите на нее, и вы получите возможность задать имя для вашей базы данных, а также тип для вашей базы данных. Здесь выберите Redis вместо Redis Stack и выберите RedisJSON и RedisSearch. После этого нажмите Activate и ваша база данных будет готова к использованию через несколько минут.
Когда база данных будет готова, сохраните в одном месте значение публичной конечной точки и пароля из разделов «Общие» и «Безопасность», поскольку вы будете использовать их позже для создания строки подключения.

Настройка учетной записи Azure для SendGrid и Storage Queue

После регистрации и входа в учетную запись Azure перейдите на портал Azure Portal, найдите «SendGrid» в верхней строке поиска и нажмите на него. Здесь вы будете создавать ресурс для Twilio SendGrid SaaS (программное обеспечение как услуга). Вы попадете на страницу создания ресурса, где вам нужно будет заполнить некоторые детали, касающиеся названия ресурса, плана и т.д.
Укажите имя для этого ресурса и выберите план «Free 100 -1 месяц», так как это будет бесплатно, и вы будете получать 100 писем в день с этим планом, что достаточно для этого учебника. После этого нажмите на Review + Subscribe, и вы попадете на вкладку Review + Subscribe, где вы сможете просмотреть заполненные вами данные. Нажмите на кнопку подписаться, и Azure создаст для вас подписку SendGrid SaaS (на подготовку к использованию уйдет несколько минут).
Когда она будет готова, вам нужно настроить учетную запись SendGrid, поэтому нажмите на кнопку «Настроить учетную запись сейчас».

После нажатия на кнопку «Configure account now» вы будете перенаправлены на новую вкладку, где вам нужно будет ввести свои учетные данные (тот же email, который вы использовали для учетной записи Azure), после чего вы попадете в приложение SendGrid, где вам нужно будет предоставить информацию для настройки вашей учетной записи SendGrid. Заполните все данные и нажмите на кнопку «Начать работу».
После выполнения всех вышеперечисленных действий вы попадете на главную страницу вашего аккаунта SendGrid, как показано ниже.

Вам необходимо получить ключ API, который вы будете использовать для вызова SendGrid API для отправки электронной почты с помощью Azure Functions. Для этого вам нужно нажать на опции Настройки в левой части страницы SendGrid, а затем выбрать опцию API-ключи из меню аккордеона (отмечена синей галочкой на изображении выше).
После этого нажмите на кнопку Создать API ключ. Вы перейдете на страницу, где вам нужно будет указать данные для вашего API-ключа, такие как имя и разрешения для вашего API-ключа.
Введите любое имя и выберите Full Access для разрешений вашего API-ключа. Затем нажмите кнопку Create & View внизу.

Теперь SendGrid покажет вам ваш новый API-ключ. Скопируйте ключ и сохраните его в надежном месте, так как в целях безопасности вы не сможете получить доступ к нему снова. Наконец, нажмите на кнопку Готово.
Ура! Вы успешно настроили аккаунт SendGrid через Azure и создали для себя ключ API, который будете использовать в дальнейшем.
Аналогичным образом, вам нужно создать очередь хранения в Azure, и для этого вы можете следовать шагам, указанным здесь.

Настройка .NET Core REST API

Откройте visual studio и создайте проект .NET Core Web API. Вы можете выбрать .NET 6 в качестве целевого фреймворка и оставить остальные настройки как есть. Как только вы нажмете на кнопку «Создать проект», visual studio загрузит проект для вас.
Сначала вам нужно добавить сущность Subscription, которая будет использоваться для моделирования документа в базе данных Redis.
Ниже приведена сущность, которую вы будете использовать:

[Document]
public partial class Subscription
{
[RedisIdField]
public string Id { get; set; }
[Indexed(Sortable = true)]
public string Email { get; set; }
[Indexed(Sortable = true)]
public DateTime SubscribedOn { get; set; }
[Searchable(Sortable = true)]
public bool IsSubscribed { get; set; }
}
Войти в полноэкранный режим Выйти из полноэкранного режима

После этого необходимо добавить конечные точки REST для нашего сервиса Newsletter Service, для чего сначала нужно создать контроллер для Subscription.

[ApiController]
[Route("[controller]")]
public class SubscriptionController : ControllerBase
{
}

Войти в полноэкранный режим Выйти из полноэкранного режима

После этого вы создадите следующие конечные точки REST

POST
/subscription
Body: Email 
---------------------------------------------------
DELETE
/subscription
Body: {Email}
---------------------------------------------------
POST
/InitializeStorage
---------------------------------------------------
POST
/newsletter
Body: {string Subject, string Body }
Вход в полноэкранный режим Выход из полноэкранного режима

Установка библиотеки Redis OM .NET и библиотеки Azure Storage Queue

Перед добавлением конечных точек Rest необходимо добавить Redis OM .NET Nuget, который мы будем использовать для подключения к базе данных Redis и выполнения операций над ней.
Для установки Redis OM .NET все, что вам нужно сделать, это добавить пакет Redis.OM NuGet в ваш проект. Это можно сделать, выполнив следующие действия

dotnet add package Redis.OM
Войти в полноэкранный режим Выйти из полноэкранного режима

Аналогичным образом вам нужно добавить Nuget для использования библиотеки очереди хранения Azure, которую вы будете использовать для отправки сообщений в очередь на Azure, которую вы создали ранее. Это можно сделать, выполнив следующую команду.

dotnet add package Azure.Storage.Queues
Войти в полноэкранный режим Выйти из полноэкранного режима

Установка зависимости от поставщика соединений Redis
Redis OM .NET использует класс RedisConnectionProvider для обработки соединений с Redis и предоставляет функции, с помощью которых вы можете взаимодействовать с Redis. Чтобы использовать его, вам нужно внедрить экземпляр RedisConnectionProvider в ваше приложение с помощью инъекции зависимостей .NET Core. Для этого необходимо поместить приведенный ниже код в файл Program.cs.

builder.Services.AddSingleton(new RedisConnectionProvider(builder.Configuration["REDIS_CONNECTION_STRING"]));
Вход в полноэкранный режим Выйти из полноэкранного режима

Также необходимо добавить REDIS_CONNECTION_STRING в наш файл appsettings.json. Чтобы получить строку подключения, вы можете использовать следующую схему:
«redis://username:password@hostname:port/4».
Имя пользователя, пароль и публичную конечную точку (host) можно найти на вкладке конфигурации базы данных. Замените эти значения в приведенной выше схеме, и вы получите строку подключения, которую нужно поместить в файл appsettings.json.
После этого провайдер будет доступен для использования в ваших контроллерах/сервисах.

Установка зависимости Azure Queue Client
Аналогичным образом необходимо зарегистрировать клиент очереди хранения Azure. Для регистрации клиента очереди необходимо поместить приведенный ниже код в файл program.cs.

builder.Services.AddAzureClients(builder =>
{
builder.AddClient<QueueClient, QueueClientOptions>((options, _, _) =>
{
options.MessageEncoding = QueueMessageEncoding.Base64;
var credential = new DefaultAzureCredential();
var queueUri = new Uri(queueURI);
return new QueueClient(queueUri, credential, options);
});
});
Вход в полноэкранный режим Выход из полноэкранного режима

Конечные точки REST

Первые три конечные точки предназначены для выполнения операций CRUD над ресурсами Subscription и Newsletter, а последняя — для конкретной цели, т.е. для создания индекса для нашей сущности Subscription в базе данных Redis, которую вы создали на Redis Cloud в предыдущем шаге.
1. Создайте конечную точку подписки
Вам необходимо создать конечную точку, которая будет принимать адрес электронной почты в качестве входных данных для создания подписки.
Вы создадите конечную точку POST, которая будет принимать SubscribeRequest, в котором вам нужно передать email, и он будет передан в Body запроса POST.
Приведенный ниже код создаст подписку с email, датой SubscribedOn и флагом isSubscribed, установленным в true.

[HttpPost]
public async Task<IActionResult> Subscribe([FromBody]SubscribeRequest subscribeRequest)
{
if (string.IsNullOrWhiteSpace(subscribeRequest.Email))
{
return BadRequest();
}
Subscription subscription = new Subscription();
subscription.Email = subscribeRequest.Email;
subscription.IsSubscribed = true;
subscription.SubscribedOn = DateTime.UtcNow;
var subscriptionCollection = _provider.RedisCollection<Subscription
();
await subscriptionCollection.InsertAsync(subscription);
return Created("/subscription", subscription.Id);
}
Вход в полноэкранный режим Выйти из полноэкранного режима

2. Удалить подписку (отменить подписку)
Вам необходимо обеспечить конечную точку, которая позволит пользователю отписаться от рассылки.
Вы создадите конечную точку DELETE, которая будет принимать UnSubscribeRequest, в котором вы передадите email. Это будет передано в Body запроса DELETE. С помощью этого запроса вы установите флаг IsSubscribed в false, если пользователь с указанным email существует в нашей системе. Ниже приведен код для этого

[HttpDelete]
public async Task<IActionResult> UnSubscribe([FromBody] UnSubscribeRequest unSubscribeRequest)
{
if (string.IsNullOrWhiteSpace(unSubscribeRequest.Email))
{
return BadRequest();
}
var subscriptionCollection = _provider.RedisCollection<Subscription>();
var existingSubscription = await subscriptionCollection.FirstOrDefaultAsync(x => x.Email == unSubscribeRequest.Email);
if(existingSubscription == null)
{
return NotFound();
}
existingSubscription.IsSubscribed = false;
_provider.Connection.Set(existingSubscription);
return Ok("/unsubscribed");
}
Вход в полноэкранный режим Выйти из полноэкранного режима

3. Создание новостной рассылки
Далее вам предстоит создать конечную точку, которая будет использоваться для создания рассылки владельцем и публикации ее в очереди azure, которая впоследствии будет обработана обработчиком рассылки.
Вы создадите конечную точку POST, которая будет принимать NewsletterRequest, в котором вам нужно передать тему и тело рассылки. Эти данные будут переданы в Body POST-запроса.
Приведенный ниже код создаст рассылку с темой и телом из запроса и получит электронные письма из Подписок, на которые вы подписаны. После создания рассылки вы будете публиковать ее в очереди Azure для асинхронной обработки службой обработки рассылки.

[HttpPost]
public async Task<IActionResult> SendNewsLetter(NewsletterRequest newsletterRequest)
{
var subscriptionCollection = _provider.RedisCollection<Subscription>();
var existingSubscription = await subscriptionCollection.ToListAsync();
if (existingSubscription != null && existingSubscription.Count > 0)
{
Newsletter newsletter = new Newsletter();
newsletter.Subject = newsletterRequest.Subject;
newsletter.Body = newsletterRequest.Body;
newsletter.Emails = existingSubscription.Where(x => x.IsSubscribed).Select(x => x.Email).ToList();
string serializedNewsLetterObject =
JsonConvert.SerializeObject(newsletter);
await _queueClient.SendMessageAsync(serializedNewsLetterObject);
}
return Accepted();
}
Вход в полноэкранный режим Выход из полноэкранного режима

4. Инициализация хранилища
Когда сущность создана, следующим шагом будет создание индекса в базе данных Redis для созданной вами модели подписки. Эта операция должна быть выполнена только один раз, поэтому вы создаете конечную точку POST для этого и запускаете ее только один раз.
Приведенный ниже код создаст RedisConnectionProvider, используя строку подключения Redis, а затем создаст индекс типа Subscription в Redis. В случае успеха будет возвращено 201 (создано), в противном случае возникнет исключение.

[HttpPost("/InitializeStorage")]
public async Task<IActionResult> InitializeStorage()
{
var provider = new RedisConnectionProvider(_configuration["REDIS_CONNECTION_STRING"]);
var isSuccess = await provider.Connection.CreateIndexAsync(typeof(Subscription));
return Created("Storage", null);
}
Вход в полноэкранный режим Выход из полноэкранного режима

Настройка Azure Function для обработки новостной рассылки

После того как вы закончили с конечными точками REST, вам предстоит создать функцию Azure, которая будет обрабатывать информационный бюллетень, опубликованный в очереди Azure, и отправлять электронные письма подписчикам.
Azure Function — это бессерверная архитектура облачной архитектуры, которая позволяет развернуть и выполнить часть кода без необходимости настройки или поддержки серверной инфраструктуры или конфигурации. Проще говоря, вы можете думать об Azure Functions как о методе, с помощью которого вы можете напрямую выполнять код в облаке, не беспокоясь о том, что представляет собой сервер, его ОС, время выполнения и т. д. Вам просто нужно предоставить код и указать платформу программирования, для которой вы пишете код, например .NET, Java, PHP, Go и т. д. Обо всем, что связано с инфраструктурой, позаботится поставщик облачных услуг. Для получения более подробной информации ознакомьтесь с документацией по Azure Functions здесь.
Теперь вы создадите Azure Function с помощью инструментов командной строки Azure Core, которые вы установили как часть предварительных условий.
Откройте оболочку командной строки и выполните приведенную ниже команду:

func init NewsletterProcessor --dotnet
Войти в полноэкранный режим Выйти из полноэкранного режима

Эта команда создаст новую папку NewsletterProcessor и сгенерирует проект .NET для Azure Functions. Перейдите в новую папку, выполнив приведенную ниже команду:

cd NewsletterProcessor
Войти в полноэкранный режим Выйти из полноэкранного режима

Этот проект пока не содержит никаких функций. Выполните следующую команду для создания Azure Function на основе триггера очереди.

func new -name NewsletterQueueProcessor -template "Queue trigger"
Войти в полноэкранный режим Выйти из полноэкранного режима

Эта команда создаст функцию C# с именем NewsletterQueueProcessor.
Вам нужно обновить функцию для обработки рассылки. Для этого вы создадите сообщение SendGrid, используя элемент рассылки, который вы получили из очереди, и это сообщение SendGrid отправит вам электронное письмо.
Ниже приведен код для этого.

public class NewsletterQueueProcessor
{
[FunctionName("NewsletterQueueProcessor")]
[return: SendGrid(ApiKey = "SENDGRID_API_KEY")]
public SendGridMessage Run([QueueTrigger("NewsletterQueue", Connection = "NewsletterQueueURI")] Newsletter newsletter, ILogger log, ExecutionContext context)
{
log.LogInformation($"C# Queue trigger function processed at: {DateTime.UtcNow}");
var config = GetConfiguration(context);
SendGridMessage message = CreateSendGridEmailMessage(newsletter, config);
return message;
}
private IConfiguration GetConfiguration(ExecutionContext context){
var config = new ConfigurationBuilder()
.SetBasePath(context.FunctionAppDirectory)
.AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables()
.Build();
return config;
}
private SendGridMessage CreateSendGridEmailMessage(Newsletter newsletter, IConfiguration config)
{
var msg = new SendGridMessage()
{
From = new EmailAddress(config["FromEmail"], config["FromName"]),
Subject = newsletter.Subject,
PlainTextContent = newsletter.Body
};
msg.AddTo(config["FromEmail"]);
List<EmailAddress> emailAddresses = new List<EmailAddress>();
foreach (var email in newsletter.Emails)
{
emailAddresses.Add(new EmailAddress(email));
}
msg.AddBccs(emailAddresses);
return msg;
}
}
Вход в полноэкранный режим Выход из полноэкранного режима

Добавление строк подключения для базы данных Redis и Azure Queue

Чтобы взаимодействовать с базой данных Redis и очередью Azure, необходимо указать строку подключения для базы данных Redis и строку подключения для очереди Azure в нашем проекте API. Для этого нужно добавить значение строки подключения для ключей REDIS_CONNECTION_STRING и AZURE_STORAGE_QUEUE_URI в файл appSettings.json нашего проекта API .NET Core.

Аналогичным образом необходимо добавить ключ SendGrid API и Azure Queue
ConnectionString в проекте Azure function. Для этого нужно добавить значения для ключа SENDGRID_API_KEY и NewsletterQueueURI в файле local.settings.json.
После установки этих значений конфигурации вы сможете запускать службы локально.

Заключение

В этой статье вы узнаете, как можно использовать RedisJSON в .NET Core вместе с функцией Azure.
Если у вас возникнут какие-либо проблемы с локальной настройкой проекта, вы можете связаться со мной по электронной почте здесь: rajivsn007@gmail.com.
Если у вас есть какие-либо отзывы об этом микросервисе Newsletter, вы можете поделиться ими на моем репозитории GitHub. До тех пор продолжайте учиться и кодить 🙂

  • Ознакомьтесь с Redis OM, клиентскими библиотеками для работы с Redis как многомодельной базой данных.
  • Используйте RedisInsight для визуализации ваших данных в Redis.
  • Подпишитесь на бесплатную базу данных Redis.

Оцените статью
devanswers.ru
Добавить комментарий