Amazon SNS to w pełni zarządzana usługa przesyłania wiadomości w komunikacji aplikacja-aplikacja (A2A) oraz aplikacja osoba (A2P).
Pierwsza z usług oparta jest na mechanizmie push, który pozwala na przesyłanie wiadomości wiele-do-wielu między systemami rozproszonymi, mikroserwisami i aplikacjami reagującymi na zdarzenia (event base architecture). Wykorzystując pojęcie tematów (topics) możemy wysyłać wiadomości do dużej liczby systemów subskrybentów, np. Amazon SQS, funkcje Lambda czy punkty końcowe HTTPS oraz Amazon Kinesis.
Drugi typ usługi pozwala na wysyłanie wiadomości do użytkowników końcowych poprzez SMS czy email.
W tym wpisie posłużymy się podejściem A2P wysyłając, na końcowym etapie, wiadomość SMS na zdefiniowany numer telefonu.
Kolejne kroki, które wykonamy w ramach tego wpisu:
utworzenie tematu w AWS SNS;
utworzenie roli, która będzie miała uprawnienia do pracy z AWS SNS, CloudWatch oraz Lambdą;
utworzenie funkcji Lambda;
dodanie notyfikacji do zdefiniowanego w powyższym kroku ‘tematu’ w celu aktywacji wyzwalacza;
sprawdzenie szczegółów wiadomości w CloudWatch.
Będą również wymagane odpowiednie kroki pozwalające na wysyłanie wiadomości tekstowych. W tym celu będziemy musieli dodać parę linii do kodu naszej funkcji Lambda - o tym oczywiście więcej w dalszej części wpisu.
Dokładny opis działania
W naszym wypadku stworzymy odpowiedni topic w usłudze SNS. W momencie publikacji powiadomienia dojdzie do uruchomienia w tle funkcji Lambda. Szczegóły dotyczące powiadomienia zostaną zarejestrowane w logach CloudWatch a wiadomość zostanie wysłana do użytkownika końcowego przy wykorzystaniu specjalnej implementacji. Spójrzcie na poniższy diagram obrazujący przebieg całego procesu:
Tworzenie tematu w SNS
Wykorzystując wyszukiwarkę usług przechodzimy do SNS:
Z poziomu panelu nawigacyjnego po lewej stronie przechodzimy do Topics a następnie klikamy przycisk Create topic:
Wypełniamy wymagane pola takie jak nazwa tematu oraz typ - w naszym wypadku wybieramy typ standardowy, pozostawiamy kolejkę typu FIFO gwarantującą wysyłanie notyfikacji w dokładnie takiej kolejności w jakiej doszło do nich w aplikacji:
Po kliknięciu przycisku znajdującego się u dołu ekranu powinniśmy dostać informację o poprawnie utworzonym temacie:
Tworzenie roli
W tym temacie jesteśmy już specjalistami. Tworzymy nową rolę, która będzie miała przypisane 3 polityki, tj. AmazonSNSFullAccess, AWSLambda_FullAccess oraz CloudWatchFullAccess:
Tworznie funkcji Lambda
Podobnie jak w poprzednich wpisach najpierw utworzymy szkielet konfiguracyjny naszej funkcji a następnie dodamy odpowiednie wyzwalacze. Proces publikacji wykonamy z poziomu środowiska Visual Studio 2019 wskazując na istniejącą konfigurację. Dodajemy bazową konfigurację definiując nazwę oraz środowisko uruchomieniowe:
W następnym kroku dodajemy nowy wyzwalacz korzystając z przycisku Add trigger:
Tym razem dodajemy wyzwalacz na poprzednio utworzony temat w ramach usługi SNS:
Ostatni krok w tej części wpisu do przygotowane kodu funkcji reagującego na wiadomości dostarczone przez SNS a następnie użycie mechanizmu logowania i dodanie tej informacji do dziennika zdarzeń (tak, abyśmy mogli podejrzeć działanie korzystając z CloudWatch):
using System.Threading.Tasks;
using Amazon.Lambda.Core;
using Amazon.Lambda.SNSEvents;
// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.SystemTextJson.DefaultLambdaJsonSerializer))]
namespace lambdasns
{
public class Function
{
/// <summary>
/// Default constructor. This constructor is used by Lambda to construct the instance. When invoked in a Lambda environment
/// the AWS credentials will come from the IAM role associated with the function and the AWS region will be set to the
/// region the Lambda function is executed in.
/// </summary>
public Function()
{
}
/// <summary>
/// This method is called for every Lambda invocation. This method takes in an SNS event object and can be used
/// to respond to SNS messages.
/// </summary>
/// <param name="evnt"></param>
/// <param name="context"></param>
/// <returns></returns>
public async Task FunctionHandler(SNSEvent evnt, ILambdaContext context)
{
context.Logger.LogLine("Funkcja Lambda i wyzwalacz SNS");
foreach (var record in evnt.Records)
{
await ProcessRecordAsync(record, context);
}
}
private async Task ProcessRecordAsync(SNSEvent.SNSRecord record, ILambdaContext context)
{
context.Logger.LogLine($"Processed record {record.Sns.Message}");
await Task.CompletedTask;
}
}
}
Proces publikowania do istniejącej funkcji jest już dla każdego znany (w moim przypadku przyjmuje poniższą postać - pamiętajcie również o zdefiniowaniu określonej polityki):
Testowanie
Pierwszy test zostanie wykonany na bazie powyższego przykładu. Jeżeli wszystko przebiegnie pomyślnie a my zobaczymy logi w dzienniku zdarzeń przystąpimy do zaimplementowania mechanizmu wysyłania wiadomości tekstowych. Funkcja Lambda zostanie uruchomiona po dodaniu powiadomienia do utworzonego wcześniej tematu SNS. Przejdźmy zatem do odpowiedniej usługi oraz dodajmy nową wiadomość (przycisk Publish message):
Dodajemy opcjonalny nagłówek wiadomości oraz treść samego powiadomienia:
Po kliknięciu przycisku Publish message przechodzimy do dziennika zdarzeń i sprawdzamy czy doszło do uruchomienia naszej funkcji:
Jak doskonale widzicie cały proces przebiegł pomyślnie a do dziennika zdarzeń zostały dodane szczegóły całego zdarzenia. Możemy teraz przejść do ostatniego kroku w tym wpisie, tj. dodanie kodu pozwalającego na wysłanie wiadomości tekstowej.
Wysyłanie wiadomości tekstowej
Wysyłanie wiadomości tekstowej będzie opierało się na usłudze Amazon SNS - wymagane będzie zainstalowanie następującej paczki w naszym projekcie: AWSSDK.SimpleNotificationService
Sama implementacja jest niezwykle prosta ponieważ bazujemy na udostępnionej funkcjonalności:
private async Task ProcessRecordAsync(SNSEvent.SNSRecord record, ILambdaContext context)
{
context.Logger.LogLine($"Processed record {record.Sns.Message}");
// Wymagana paczka: AWSSDK.SimpleNotificationService
var snsClient = new AmazonSimpleNotificationServiceClient(RegionEndpoint.USEast1);
// Reqest zawiera treść wiadomości oraz numer telefonu
var request = new PublishRequest
{
Message = record.Sns.Message,
PhoneNumber = "+48XXXXXXXXX"
};
try
{
var response = await snsClient.PublishAsync(request);
}
catch (Exception ex)
{
// W razie niepowodzenia logujemy stosowną informację
context.Logger.LogLine($"Error sending message: {ex}");
}
await Task.CompletedTask;
}
Po poprawnym opublikowaniu zaktualizowanego kodu dodajemy jeszcze raz wiadomość używając przycisku Publish message z poziomu okna zarządzania usługą SNS. Po chwili powinniśmy dostać wiadomość tekstową na podany numer telefonu: