Описание#
Является сервисом-пройслойкой, который отвечает только за один тип уведомлений - отправку сообщений по электронной почте.
Принцип работы#
Сервис принимает gRPC-запрос SendNotification от NotificationService.
Модель входных данных в SendNotification#
message NotificationRequest {
string title = 1; // тема сообщения
string category_message = 2; // категория сообщени (required)
int32 contact_type = 3; // тип контакта (required)
StringValue user_UUID = 4; // уникальный идентификатор пользователя (optional)
StringValue message = 5; // текст сообщения (optional)
repeated string contacts = 6; // email-адреса
Int32Value secret_code = 7; // код подтверждения
}
Категории сообщений#
enum MessageCategories {
NOT_USED = 0; // не используется
VERIFY_CONTACT = 1; // подтверждение контакта
SOME_INFO = 2; // информационное письмо
RESET_PASSWORD = 3; // сброс пароля
SIGN_IN = 4; // вход/авторизация
CREATE_REGISTRATION = 5; // уведомление о регистрации на мероприятие
SIGN_UP_VERIFY = 6; // подтверждениие регистрации аккаунта
}
Обработчик проверяет категорию и тему сообщения, в случае если категория SOME_INFO и заголовок пуст, возвращает status.Error() с соответствующим кодом и текстом.
Далее вызывает метод SendNotification из usecase слоя.
Этот метод кладёт данные в буферизированный канал.
На один инстанс сервиса запущен один worker().
Что он делает:
- Каждые 250мс проверяет очередь.
- Берёт запрос из канала и вызывает для него
send().
Что делает send():
- В
Switch'итсяпо категории сообщения, если она:VERIFY_CONTACT,RESET_PASSWORD,SIGN_IN,SIGN_UP_VERIFY, то:- Устанавливает
ruлокаль. - Вызывает метод
confirmationCodeTemplateFunc(), где происходит подгонка сообщения под шаблон. - Полю Message присваивается значение переменной, которая вернулась из
confirmationCodeTemplateFunc(). - В случае неудачи - возвращается ошибка.
- Устанавливает
- Если же категория сообщения
CREATE_REGISTRATION, то:- Проверяется по
Messageнаnil, если оноnil, то ошибка логгируется в Sentry. - Вызывает метод
createRegistration(), где происходит подгонка сообщения под соответствующий шаблон. - В случае неудачи - возвращается ошибка.
- Проверяется по
- Далее создаётся структура типа
&mail.Mail{}, гдеemailMessage := &mail.Email{ To: req.Contacts, // массив email-адресов получателей From: uc.cfg.SMTP.Sender, // адрес отправителя Subject: req.Title, // заголовок письма HTML: []byte(*req.Message), // готовый HTML-текст письма Headers: textproto.MIMEHeader{}, // доп. заголовки (пустые, не используются) } - У
emailMessageвызывается методSend(), куда передаётся адрес SMTP-сервера и объект аутентификации. В случае ошибки логгирует её в Span, создаёт структуруEmaillogиз repo-слоя, куда записывает данные о контексте ошибки, вызывает методSaveLogдля сохранения этих данных в БД, возвращает ошибку. - В случае успеха, создаёт такую же структуру
Emaillog, но со значением поляErrorText-nil, также передаёт её в методSaveLogи в качестве ошибки возвращаетnil.