예제 #1
0
        public void TestFunction()
        {
            var function = new Function();
            var context  = new TestLambdaContext();

            SNSEvent.SNSMessage snsMessage = new SNSEvent.SNSMessage {
                Message   = "{\"notificationType\":\"Bounce\",\"bounce\":{\"bounceType\":\"Permanent\",\"feedbackId\":\"feedback_id\",\"bouncedRecipients\":[{\"emailAddress\":\"[email protected]\"}]}}",
                Timestamp = DateTime.Parse("1/1/1990")
            };
            SNSEvent.SNSRecord snsRecord = new SNSEvent.SNSRecord {
                EventSource          = "event_source",
                EventSubscriptionArn = "event_subscription_arn",
                EventVersion         = "event_version",
                Sns = snsMessage
            };
            List <SNSEvent.SNSRecord> recordList = new List <SNSEvent.SNSRecord>();

            recordList.Add(snsRecord);
            SNSEvent snsEvent = new SNSEvent {
                Records = recordList
            };

            var retval = function.FunctionHandler(snsEvent, context);

            Assert.Equal("okay", retval.Result);
        }
        /// <summary>
        /// The <see cref="ProcessMessageStreamAsync(Stream)"/> method is overridden to
        /// provide specific behavior for this base class.
        /// </summary>
        /// <remarks>
        /// This method cannot be overridden.
        /// </remarks>
        /// <param name="stream">The stream with the request payload.</param>
        /// <returns>The task object representing the asynchronous operation.</returns>
        public override sealed async Task <Stream> ProcessMessageStreamAsync(Stream stream)
        {
            // read stream into memory
            LogInfo("reading stream body");
            string snsEventBody;

            using (var reader = new StreamReader(stream)) {
                snsEventBody = reader.ReadToEnd();
            }
            var stopwatch = Stopwatch.StartNew();
            var metrics   = new List <LambdaMetric>();

            // process received sns record (there is only ever one)
            try {
                // sns event deserialization
                LogInfo("deserializing SNS event");
                try {
                    var snsEvent = LambdaSerializer.Deserialize <SNSEvent>(snsEventBody);
                    _currentRecord = snsEvent.Records.First().Sns;

                    // message deserialization
                    LogInfo("deserializing message");
                    var message = Deserialize(CurrentRecord.Message);

                    // process message
                    LogInfo("processing message");
                    await ProcessMessageAsync(message);

                    // record successful processing metrics
                    stopwatch.Stop();
                    var now = DateTimeOffset.UtcNow;
                    metrics.Add(("MessageSuccess.Count", 1, LambdaMetricUnit.Count));
                    metrics.Add(("MessageSuccess.Latency", stopwatch.Elapsed.TotalMilliseconds, LambdaMetricUnit.Milliseconds));
                    metrics.Add(("MessageSuccess.Lifespan", (now - CurrentRecord.GetLifespanTimestamp()).TotalSeconds, LambdaMetricUnit.Seconds));
                    return("Ok".ToStream());
                } catch (Exception e) {
                    LogError(e);
                    try {
                        // attempt to send failed message to the dead-letter queue
                        await RecordFailedMessageAsync(LambdaLogLevel.ERROR, FailedMessageOrigin.SQS, LambdaSerializer.Serialize(snsEventBody), e);

                        // record failed processing metrics
                        metrics.Add(("MessageDead.Count", 1, LambdaMetricUnit.Count));
                    } catch {
                        // NOTE (2020-04-22, bjorg): since the message could not be sent to the dead-letter queue,
                        //  the next best action is to let Lambda retry it; unfortunately, there is no way
                        //  of knowing how many attempts have occurred already.

                        // unable to forward message to dead-letter queue; report failure to lambda so it can retry
                        metrics.Add(("MessageFailed.Count", 1, LambdaMetricUnit.Count));
                        throw;
                    }
                    return($"ERROR: {e.Message}".ToStream());
                }
            } finally {
                _currentRecord = null;
                LogMetric(metrics);
            }
        }
예제 #3
0
 //--- Extension Methods ---
 public static DateTimeOffset GetLifespanTimestamp(this SNSEvent.SNSMessage message)
 {
     // a custom "SentTimestamp" message attribute takes precedence over the record "SentTimestamp" attribute
     if (
         message.MessageAttributes.TryGetValue(SENT_TIME_ATTRIBUTE, out var sentTimeMessageAttribute) &&
         (sentTimeMessageAttribute.Type == "String") &&
         long.TryParse(sentTimeMessageAttribute.Value, out var sentTimeEpoch)
         )
     {
         return(DateTimeOffset.FromUnixTimeMilliseconds(sentTimeEpoch));
     }
     return(message.Timestamp.ToUniversalTime());
 }
예제 #4
0
        private async Task ProcessMessageAsync(SNSEvent.SNSMessage message)
        {
            if (message == null || message.Message == null || message.Message.Contains("Error:"))
            {
                LambdaLogger.Log($"Error: {message?.Message}");
            }

            LambdaLogger.Log($"Processed message {message?.Message}");

            EventMessage eventMessage = JsonConvert.DeserializeObject <EventMessage>(message?.Message);

            await RegisterUser(eventMessage);
        }
예제 #5
0
        public async Task CompleteTask(SNSEvent.SNSMessage message)
        {
            if (message.Message == "available")
            {
                await stepFunctionsClient.SendTaskSuccessAsync(new SendTaskSuccessRequest
                {
                    Output    = Serialize(new { Status = message.Message }),
                    TaskToken = message.MessageAttributes["TaskToken"].Value
                });

                return;
            }

            await stepFunctionsClient.SendTaskFailureAsync(new SendTaskFailureRequest
            {
                Cause     = message.Message,
                TaskToken = message.MessageAttributes["TaskToken"].Value
            });
        }
        /// <summary>
        /// The <see cref="ProcessMessageStreamAsync(Stream)"/> method is overridden to
        /// provide specific behavior for this base class.
        /// </summary>
        /// <remarks>
        /// This method cannot be overridden.
        /// </remarks>
        /// <param name="stream">The stream with the request payload.</param>
        /// <returns>The task object representing the asynchronous operation.</returns>
        public override sealed async Task <Stream> ProcessMessageStreamAsync(Stream stream)
        {
            // read stream into memory
            LogInfo("reading stream body");
            string snsEventBody;

            using (var reader = new StreamReader(stream)) {
                snsEventBody = reader.ReadToEnd();
            }

            // process received sns record (there is only ever one)
            try {
                // sns event deserialization
                LogInfo("deserializing SNS event");
                var snsEvent = DeserializeJson <SNSEvent>(snsEventBody);
                CurrentRecord = snsEvent.Records.First().Sns;

                // message deserialization
                LogInfo("deserializing message");
                var message = Deserialize(CurrentRecord.Message);

                // process message
                LogInfo("processing message");
                await ProcessMessageAsync(message);

                return("Ok".ToStream());
            } catch (Exception e) when(!(e is LambdaRetriableException))
            {
                LogError(e);
                await RecordFailedMessageAsync(LambdaLogLevel.ERROR, FailedMessageOrigin.SNS, snsEventBody, e);

                return($"ERROR: {e.Message}".ToStream());
            } finally {
                CurrentRecord = null;
            }
        }
예제 #7
0
 private string GetMessageQueueName(SNSEvent.SNSMessage sns)
 {
     return(sns.Message);
 }
예제 #8
0
        public void Setup()
        {
            // APIGatewayProxy
            _baseAPIGatewayProxyRequest = new APIGatewayProxyRequest
            {
                HttpMethod = "POST",
                Path       = "/test/path",
            };

            _baseAPIGatewayProxyResponse = new APIGatewayProxyResponse
            {
                StatusCode = (int)HttpStatusCode.OK,
            };

            // ApplicationLoadBalancer
            var albRequestContext = new ApplicationLoadBalancerRequest.ALBRequestContext
            {
                Elb = new ApplicationLoadBalancerRequest.ElbInfo()
            };

            albRequestContext.Elb.TargetGroupArn = TestArn;
            _baseApplicationLoadBalancerRequest  = new ApplicationLoadBalancerRequest
            {
                HttpMethod     = "POST",
                Path           = "/test/path",
                RequestContext = albRequestContext,
            };

            _baseApplicationLoadBalancerResponse = new ApplicationLoadBalancerResponse
            {
                StatusCode = (int)HttpStatusCode.OK,
            };

            // SQSEvent
            var sqsRecord = new SQSEvent.SQSMessage
            {
                EventSourceArn = TestArn
            };

            _baseSQSEvent = new SQSEvent
            {
                Records = new List <SQSEvent.SQSMessage> {
                    sqsRecord
                },
            };

            // SNSEvent
            var snsMessaage = new SNSEvent.SNSMessage()
            {
                Message = "Test Message",
            };
            var snsRecord = new SNSEvent.SNSRecord
            {
                EventSubscriptionArn = TestArn,
                Sns = snsMessaage
            };

            _baseSNSEvent = new SNSEvent
            {
                Records = new List <SNSEvent.SNSRecord> {
                    snsRecord
                },
            };

            // KinesisEvent
            var kinesisRecord = new KinesisEvent.KinesisEventRecord
            {
                EventSourceARN = TestArn
            };

            _baseKinesisEvent = new KinesisEvent
            {
                Records = new List <KinesisEvent.KinesisEventRecord> {
                    kinesisRecord
                },
            };

            // S3Event
            var s3Record = new Amazon.S3.Util.S3EventNotification.S3EventNotificationRecord
            {
                S3 = new Amazon.S3.Util.S3EventNotification.S3Entity
                {
                    Bucket = new Amazon.S3.Util.S3EventNotification.S3BucketEntity
                    {
                        Arn = TestArn
                    }
                }
            };

            _baseS3Event = new S3Event
            {
                Records = new List <Amazon.S3.Util.S3EventNotification.S3EventNotificationRecord> {
                    s3Record
                },
            };

            // DynamoDBEvent
            var dynamoDBRecord = new DynamoDBEvent.DynamodbStreamRecord
            {
                EventSourceArn = TestArn
            };

            _baseDynamoDBEvent = new DynamoDBEvent
            {
                Records = new List <DynamoDBEvent.DynamodbStreamRecord> {
                    dynamoDBRecord
                },
            };

            // KinesisFirehoseEvent
            _baseKinesisFirehoseEvent = new KinesisFirehoseEvent
            {
                DeliveryStreamArn = TestArn,
            };
        }