I had a requirement recently where I needed to run a Monitoring code hourly to gather and plot some stats. With monitor duration of 1 second and total executions of 24/day, serverless seemed to be the way to go. However Serverless being an event driven world, I needed some way to trigger my Lambda.
For these kind of use cases, AWS provides Cloud Watch Events. From the docs
To trigger this event, I setup a simple Rule
The rule is to trigger the LambdaFunction I created every minute. The Cloud Watch Event received as input was used as is:
The execution logs in Cloud Watch are:
On running, the lambda failed:
I updated my Lambda accordingly
I updated the Lambda function to take string as input
The result is
For these kind of use cases, AWS provides Cloud Watch Events. From the docs
Amazon CloudWatch Events delivers a near real-time stream of system events that describe changes in Amazon Web Services (AWS) resources.What I needed was a new event triggered on a schedule. Consider the simple Lambda I setup for this exercise
public class LoggerLambda implements RequestHandler<ScheduledEvent, Void> { @Override public Void handleRequest(ScheduledEvent input, Context context) { LambdaLogger logger = context.getLogger(); logger.log("In Handler: Executing " + context.getFunctionName() + ", " + context.getFunctionVersion()); logger.log(input.toString()); //This input is not really used now return null; } }The code receives a ScheduledEvent instance, which represents a scheduled CloudWatch Event. It simply logs the event.
To trigger this event, I setup a simple Rule
The rule is to trigger the LambdaFunction I created every minute. The Cloud Watch Event received as input was used as is:
The execution logs in Cloud Watch are:
START RequestId: b6695a38-50da-4b56-89e5-4a4c4755ce3a Version: $LATEST In Handler: Executing ScheduledLambda, $LATEST {account: 083144642440,region: us-east-1,detail: {},detailType: Scheduled Event,source: aws.events,id: f9ca55df-c7e2-3094-6f2d-1a2a267ec033,time: 2020-04-25T17:31:42.000Z,resources: [arn:aws:events:us-east-1:083144642440:rule/TestLambdaWithDefaultEvent]} END RequestId: b6695a38-50da-4b56-89e5-4a4c4755ce3aAs seen the ScheduledEvent object includes all fields we saw on the CloudWatch Event console. decided to just pass part of the matched Event instead.
On running, the lambda failed:
START RequestId: 7dcdb189-1bc1-4344-be8b-bc3690b7295c Version: $LATEST An error occurred during JSON parsing: java.lang.RuntimeException java.lang.RuntimeException: An error occurred during JSON parsing Caused by: java.io.UncheckedIOException: com.fasterxml.jackson.databind.JsonMappingException:
Can not instantiate value of type [simple type, class com.amazonaws.services.lambda.runtime.events.ScheduledEvent]
from String value ('0'); no single-String constructor/factory method at [Source: lambdainternal.util.NativeMemoryAsInputStream@56aac163; line: 1, column: 1] Caused by: com.fasterxml.jackson.databind.JsonMappingException:
Can not instantiate value of type [simple type, class com.amazonaws.services.lambda.runtime.events.ScheduledEvent]
from String value ('0'); no single-String constructor/factory method at [Source: lambdainternal.util.NativeMemoryAsInputStream@56aac163; line: 1, column: 1] at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148) at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:878) at com.fasterxml.jackson.databind.deser.ValueInstantiator._createFromStringFallbacks(ValueInstantiator.java:281) at com.fasterxml.jackson.databind.deser.std.StdValueInstantiator.createFromString(StdValueInstantiator.java:284) at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromString(BeanDeserializerBase.java:1176) at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:145) at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:136) at com.fasterxml.jackson.databind.ObjectReader._bindAndClose(ObjectReader.java:1511) at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:1102)The $version when sent as input to my Lambda, it cannot be parsed into a ScheduledEvent. On updating the code
public class LoggerLambda implements RequestHandler<String, Void> { @Override public Void handleRequest(String input, Context context) { LambdaLogger logger = context.getLogger(); logger.log("In Handler: Executing " + context.getFunctionName() + ", " + context.getFunctionVersion()); logger.log(input); //This input is not really used now return null; } }This worked as the String input could be loaded into my Lambda:
START RequestId: f6f421cc-9507-4dc0-8d30-455e040ada5a Version: $LATEST In Handler: Executing ScheduledLambda, $LATEST 0 END RequestId: f6f421cc-9507-4dc0-8d30-455e040ada5a REPORT RequestId: f6f421cc-9507-4dc0-8d30-455e040ada5a Duration: 15.22 ms Billed Duration: 100 ms Memory Size: 512 MB Max Memory Used: 75 MB Init Duration: 309.39 msSimilarly if we wanted to pass a constant (has to be Json form)
I updated my Lambda accordingly
public class LoggerLambda implements RequestHandler<ComputeEntity, Void> { @Override public Void handleRequest(ComputeEntity input, Context context) { LambdaLogger logger = context.getLogger(); logger.log("In Handler: Executing " + context.getFunctionName() + ", " + context.getFunctionVersion()); logger.log(input.toString()); return null; } }The json class
public class ComputeEntity { private String type; private Entity entity; public enum Entity { Employee, Supervisor, Customer } @Override public String toString() { return "ComputeEntity{" + "type='" + type + '\'' + ", entity=" + entity + '}'; } //getter setters }On running this, Lambda converted my static Json into the POJO class object while executing my function:
START RequestId: b8404982-3c03-46fa-b755-5d67bae53f9e Version: $LATEST In Handler: Executing ScheduledLambda, $LATEST ComputeEntity{type='computeArrears', entity=Employee} END RequestId: b8404982-3c03-46fa-b755-5d67bae53f9e REPORT RequestId: b8404982-3c03-46fa-b755-5d67bae53f9e Duration: 72.24 ms Billed Duration: 100 ms Memory Size: 512 MB Max Memory Used: 79 MB Init Duration: 351.94 msThe last option available is Input Transformer which allows you to build a String input using details from the Event
I updated the Lambda function to take string as input
The result is
START RequestId: 9847937c-bf57-477e-a29c-2909ee8db831 Version: $LATEST In Handler: Executing ScheduledLambda, $LATEST The time of event is 2020-04-25T19:58:27Z and id is 9956c6df-64ea-6a6a-0812-61ad6e829218 END RequestId: 9847937c-bf57-477e-a29c-2909ee8db831 REPORT RequestId: 9847937c-bf57-477e-a29c-2909ee8db831 Duration: 26.95 ms Billed Duration: 100 ms Memory Size: 512 MB Max Memory Used: 76 MB Init Duration: 325.88 msI was interested if we could add stuff into the original Event. For example the details field is blank for custom events, however that is not allowed. We could:
- either pass the Event as is
- send part of the Scheduled Event forward
- Send a constant JSON message
- Send a custom String message built from the Event
Well research and resourceful content indeed. Also visit here: Feeta.pk - apartments for sale in Islamabad . Thank you for this useful material! It’s amazing!
ReplyDelete