逐步学习AWS上的无服务器-SNS
#aws #javascript #教程 #serverless

tl; dr

在本系列中,我尝试解释AWS上无服务器的基础知识,以使您能够构建自己的无服务器应用程序。使用last article,我们发现了如何使用Aurora serverless在AWS上部署和与SQL数据库进行部署和交互。在本文中,我们将解决SNS主题,这些主题允许在您的应用程序中创建酒吧/子模式!

我们今天将做什么?

在本文中,我们将创建一个SNS主题,并使用它将通知发送到多个Lambda功能。我们将看到如何利用它来将有针对性的通知发送到我们应用程序的特定部分,具体取决于上下文,以及如何使用它将其解除。

â€i,如果您想要更多的â€

,请定期发布无服务器内容

Follow me on twitter 🚀

亚马逊简单通知服务(SNS)

什么是SNS?

Amazon SNS是一家无服务器/子服务。它允许您创建主题。主题有生产者和消费者。生产者可以将消息发布到一个主题,消费者可以订阅主题以接收消息。当一条消息发布到主题中时,每个消费者最终都会收到它,它称为粉丝模式。

这是一个非常强大的模式,因为它可以使生产者和消费者解脱。生产者不需要知道谁会消耗他们的信息,消费者不需要知道谁会生产它们。单个动作可以触发多个消费者。

SNS还使您可以在主题上创建过滤器,以便消费者可以订阅一部分消息。这允许创建有针对性的通知,并使您的应用程序更加失望。例如,请求发送lambda函数只能对与交货请求有关的消息感兴趣,而不是对与付款请求有关的消息感兴趣。

让我们构建一个简单的应用程序来演示SNS!

今天,我们将构建一个非常简单的应用程序:

  • OrderItem lambda是由REST API上的POST请求触发的。用户可以指定他是否要收到通知,以及是否要要求订单交货。
  • OrderItem lambda将向SNS主题发布一条消息,并提供订单详细信息。
  • 下游,SNS主题将触发三个lambda功能:

    • ExecuteOrder lambda,将模拟付款。
    • RequestDelivery lambda,该lambda将模拟交付,只有在用户请求时。
    • Notification lambda,该lambda将向用户发送通知,只有在他要求的情况下。

我们应用的架构看起来像这样:

Architecture

每个动作都会由简单的console.log模拟,但是借助整个系列的组合知识,您可以在DynamoDB,S3,SES或任何其他AWS服务上轻松替换它们!

创建一个SNS主题

要构建此应用程序,我们将使用AWS CDK。如果您不熟悉它,建议您阅读start of my series,我可以在其中详细谈论它。我们将创建一个新的CDK项目,向其添加@aws-cdk/aws-sns软件包,并在堆栈中创建一个新的SNS主题,以及一个触发我们的OrderItem Lambda的API网关。

import * as cdk from 'aws-cdk-lib';

import path from 'path';

export class ArticleSNS extends cdk.Stack {
  constructor(scope: Construct, id: string) {
    super(scope, id);

    const topic = new cdk.aws_sns.Topic(this, 'topic');

    const api = new cdk.aws_apigateway.RestApi(this, 'api', {});

    const orderItem = new cdk.aws_lambda_nodejs.NodejsFunction(this, 'OrderItem', {
      entry: path.join(__dirname, 'orderItem', 'handler.ts'),
      handler: 'handler',
      environment: {
        TOPIC_ARN: topic.topicArn,
      },
    });
    topic.grantPublish(orderItem);
    api.root.addResource('orderItem').addMethod('POST', new cdk.aws_apigateway.LambdaIntegration(orderItem));
  }
}

请注意,我们将publish许可授予OrderItem lambda,以便它可以将消息发布给主题。我们还将主题Arn作为环境变量传递给lambda,以便它可以使用它来发布消息。

将lambdas订阅为SNS主题

现在,让我们创建3个下游lambda函数并将其订阅到主题。我们将在主题上实现过滤器,以便每个lambda函数仅接收感兴趣的消息。

// ... previous code

const executeOrder = new cdk.aws_lambda_nodejs.NodejsFunction(this, 'ExecuteOrder', {
  entry: path.join(__dirname, 'executeOrder', 'handler.ts'),
  handler: 'handler',
});
topic.addSubscription(new cdk.aws_sns_subscriptions.LambdaSubscription(executeOrder));

const requestDelivery = new cdk.aws_lambda_nodejs.NodejsFunction(this, 'RequestDelivery', {
  entry: path.join(__dirname, 'requestDelivery', 'handler.ts'),
  handler: 'handler',
});
topic.addSubscription(
  new cdk.aws_sns_subscriptions.LambdaSubscription(requestDelivery, {
    filterPolicy: {
      // Only triggers when the "requestDelivery" attribute is set to "true"
      requestDelivery: cdk.aws_sns.SubscriptionFilter.stringFilter({ allowlist: ['true'] }),
    },
  }),
);

const sendNotification = new cdk.aws_lambda_nodejs.NodejsFunction(this, 'SendNotification', {
  entry: path.join(__dirname, 'sendNotification', 'handler.ts'),
  handler: 'handler',
});
topic.addSubscription(
  new cdk.aws_sns_subscriptions.LambdaSubscription(sendNotification, {
    filterPolicy: {
      // Only triggers when the "sendNotification" attribute is set to "true"
      sendNotification: cdk.aws_sns.SubscriptionFilter.stringFilter({ allowlist: ['true'] }),
    },
  }),
);

看,没有什么太复杂了。使用FilterPolicy参数,我们可以指定哪些消息应触发lambda函数。在我们的情况下,我们只有在将requestDelivery属性设置为true时才能触发requestDelivery lambda,并且仅在将sendNotification属性设置为true时,sendnotification lambda才能。

将消息发布到SNS主题

最后,有趣的部分:是时候编写lambdas的代码了!让我们从OrderItem lambda开始,该lambda将将消息发布到主题中。

// orderItem/handler.ts
import { PublishCommand, SNSClient } from '@aws-sdk/client-sns';

const client = new SNSClient({});

export const handler = async (event: { body: string }): Promise<{ statusCode: number; body: string }> => {
  const topicArn = process.env.TOPIC_ARN;

  if (topicArn === undefined) {
    throw new Error('TOPIC_ARN is undefined');
  }

  const { requestDelivery, sendNotification, item, quantity } = JSON.parse(event.body) as {
    requestDelivery?: boolean;
    sendNotification?: boolean;
    item?: string;
    quantity?: number;
  };

  if (requestDelivery === undefined || sendNotification === undefined || item === undefined || quantity === undefined) {
    return {
      statusCode: 400,
      body: 'Bad request',
    };
  }

  await client.send(
    new PublishCommand({
      Message: JSON.stringify({ item, quantity }),
      TopicArn: topicArn,
      MessageAttributes: {
        sendNotification: {
          DataType: 'String',
          StringValue: sendNotification.toString(),
        },
        requestDelivery: {
          DataType: 'String',
          StringValue: requestDelivery.toString(),
        },
      },
    }),
  );

  return {
    statusCode: 200,
    body: 'Item ordered',
  };
};

此代码做三件事:

  • 它从环境变量中获取主题。
  • 它解析了请求的主体,并提取requestDeliverysendNotificationitemquantity属性。
  • 它向主题发布消息:
    • 消息主体包含业务数据itemquantity
    • 根据请求,属性requestDeliverysendNotification设置为truefalse。此属性是我们之前定义的过滤器将使用的属性。

对于三个下游的lambdas,我们将使用Console.log是否能够在AWS控制台上看到是否触发。

// executeOrder/handler.ts
export const handler = async (event: {
  Records: {
    Sns: {
      Message: string;
    };
  }[];
}): Promise<void> => {
  event.Records.forEach(({ Sns: { Message } }) => {
    const { item, quantity } = JSON.parse(Message) as { item: string; quantity: number };

    console.log(`ORDER EXECUTED - Item: ${item}, Quantity: ${quantity}`);
  });
};

在此lambda中,我记录了从主题中收到的消息的内容。有趣的部分是事件参数的类型:它是记录的数组。这是因为SNS可以一次发送多个消息,因此我们需要处理这种情况。

// requestDelivery/handler.ts
export const handler = (): Promise<void> => {
  console.log('DELIVERY REQUESTED');
};
// sendNotification/handler.ts
export const handler = (): Promise<void> => {
  console.log('NOTIFICATION SENT');
};

正如我已经说过的,如果您从一开始就遵循了本系列,则应该能够用真实的操作替换此游戏机。LOG语句,例如更新DynamoDB或SQL数据库,与SES发送电子邮件或其他任何内容!

是时候测试它了!

首先,让我们通过AWS CDK部署应用程序:

npm run cdk deploy

然后,让我们通过向Postman发送API呼叫来测试它:

在第一个通话中,我将sendNotificationrequestDelivery设置为false。正如预期的那样,仅触发ExecuteOrder lambda。我们可以在CloudWatch中看到logs,其中包含消息的内容。

Postman

CloudWatch

在第二个通话中,我将sendNotification设置为true。触发了ExecuteOrderSendNotification lambdas。我们可以在CloudWatch中看到SendNotification的日志。

Postman

CloudWatch

在第三个通话中,我将requestDelivery设置为true。触发了ExecuteOrderRequestDelivery lambdas。我们可以在CloudWatch中看到RequestDelivery的日志。

Postman

CloudWatch

结论

这是对SNS的非常浅的介绍。我演示了如何创建主题,订阅lambdas并向其发布消息。我没有编写任何实际副作用,但是您应该使用本系列之前的文章中获得的知识来独自做到这一点。

SNS还允许向移动应用程序发送电子邮件,SMS或推送通知,但我在本文中没有介绍此信息。将来我可能会再写一篇有关它的文章!

我计划每两月继续这一系列文章。我已经涵盖了简单的lambda函数和REST API的创建,并与DynamoDB数据库和S3存储桶进行了交互。您可以在我的repository上遵循此进度!我将介绍新主题,例如前端部署,类型安全,更高级的模式等...如果您有任何建议,请随时与我联系!

,如果您可以与您的朋友和同事分享这篇文章,我真的很感激。这将有助于我发展听众。另外,不要忘记在下一篇文章发行时订阅要更新!

我想在这里保持联系是我的twitter account。我经常发布或重新发布有关AWS和无服务器的有趣内容,请随时关注我!

Follow me on twitter 🚀