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 ofWhat I needed was a new event triggered on a schedule. Consider the simple Lambda I setup for this exercise
system events that describe changes in Amazon Web Services (AWS) resources.
publicclass LoggerLambda implements RequestHandler<ScheduledEvent, Void> {The code receives a ScheduledEvent instance, which represents a scheduled CloudWatch Event. It simply logs the event.
@Override
publicVoid 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
returnnull;
}
}
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: $LATESTAs seen the ScheduledEvent object includes all fields we saw on the CloudWatch Event console. decided to just pass part of the matched Event instead.
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-4a4c4755ce3a
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 methodThe $version when sent as input to my Lambda, it cannot be parsed into a ScheduledEvent. On updating the code
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)
publicclass LoggerLambda implements RequestHandler<String, Void> {This worked as the String input could be loaded into my Lambda:
@Override
publicVoid 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
returnnull;
}
}
START RequestId: f6f421cc-9507-4dc0-8d30-455e040ada5a Version: $LATESTSimilarly if we wanted to pass a constant (has to be Json form)
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 ms
I updated my Lambda accordingly
publicclass LoggerLambda implements RequestHandler<ComputeEntity, Void> {The json class
@Override
publicVoid handleRequest(ComputeEntity input, Context context) {
LambdaLogger logger = context.getLogger();
logger.log("In Handler: Executing " + context.getFunctionName() + ", " + context.getFunctionVersion());
logger.log(input.toString());
returnnull;
}
}
publicclass ComputeEntity {On running this, Lambda converted my static Json into the POJO class object while executing my function:
privateString type;
privateEntity entity;
publicenumEntity {
Employee,
Supervisor,
Customer
}
@Override
publicString toString() {
return"ComputeEntity{" + "type='" + type + '\'' + ", entity=" + entity + '}';
}
//getter setters
}
START RequestId: b8404982-3c03-46fa-b755-5d67bae53f9e Version: $LATESTThe last option available is Input Transformer which allows you to build a String input using details from the Event
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 ms
I updated the Lambda function to take string as input
The result is
START RequestId: 9847937c-bf57-477e-a29c-2909ee8db831 Version: $LATESTI 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:
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 ms
- 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




