Paweł Łukasiewicz
2022-05-10
Paweł Łukasiewicz
2022-05-10
Udostępnij Udostępnij Kontakt
Wprowadzenie

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:

  1. utworzenie tematu w AWS SNS;
  2. utworzenie roli, która będzie miała uprawnienia do pracy z AWS SNS, CloudWatch oraz Lambdą;
  3. utworzenie funkcji Lambda;
  4. dodanie notyfikacji do zdefiniowanego w powyższym kroku ‘tematu’ w celu aktywacji wyzwalacza;
  5. 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: AWS SNS: przykładowa architektura

Tworzenie tematu w SNS

Wykorzystując wyszukiwarkę usług przechodzimy do SNS: AWS SNS: wyszukiwarka usług

Z poziomu panelu nawigacyjnego po lewej stronie przechodzimy do Topics a następnie klikamy przycisk Create topic: AWS SNS: tworzenie tematu

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: AWS SNS: ustawienia tematu

Po kliknięciu przycisku znajdującego się u dołu ekranu powinniśmy dostać informację o poprawnie utworzonym temacie: AWS SNS: pomyslnie utworzony temat

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: AWS SNS: tworzenie roli

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: AWS SNS: tworzenie funkcji

W następnym kroku dodajemy nowy wyzwalacz korzystając z przycisku Add trigger: AWS SNS: dodawanie wyzwalacza

Tym razem dodajemy wyzwalacz na poprzednio utworzony temat w ramach usługi SNS: AWS SNS: ustawienie wyzwalacza

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): AWS SNS: publikowanie funkcji Lambda

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): AWS SNS: publikowanie wiadomości

Dodajemy opcjonalny nagłówek wiadomości oraz treść samego powiadomienia: AWS SNS: nagłówek wiadomości Po kliknięciu przycisku Publish message przechodzimy do dziennika zdarzeń i sprawdzamy czy doszło do uruchomienia naszej funkcji: AWS SNS: dziennik zdarzeń 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: AWS SNS: notyfikacja otrzymana na numer telefonu