AWS Lambda makes it incredibly easy and cost-effective (no charge when code is not running) to run your code at arbitrary scale in the cloud. Simply write the handler code for your function and upload it to Lambda. The service takes care of hosting and scaling the function for you.
AWS Lambda in Kotlin using Spring Cloud Function
Upasana | August 01, 2020 | 5 min read | 455 views | AWS Tutorials
In this tutorial we will use Spring Cloud Functions (version 2.x) in Kotlin to create and deploy a simple AWS Lambda.
Spring Cloud Function
Spring cloud function project has following goals:
-
Promote the implementation of business logic via functions.
-
Decouple the development lifecycle of business logic from any specific runtime target so that the same code can run as a web endpoint, a stream processor, or a task.
-
Support a uniform programming model across serverless providers, as well as the ability to run standalone (locally or in a PaaS).
-
Enable Spring Boot features (auto-configuration, dependency injection, metrics) on serverless providers.
Outline of this tutorial
-
Create Spring Cloud Function for the Number reversal program
-
Upload Spring Cloud Function to AWS Lambda
-
Use Java Client to invoke the Lambda Function
-
Use Kotlin Client to invoke the Lambda Function
Create Spring Cloud Function Project
Create a new Spring Boot project using template at Spring Initializer.
Problem statement
We will create a simple lambda function that takes an input number and reverses it.
Lets define the domain models: We need wrapper methods for accepting input and providing result. Jackson will handle the JSON marshalling for these objects.
package com.shunya.reverse
class NumberInput {
var input: Long = 0
}
class NumberOutput {
var result: Long? = null
}
Now lets create a FunctionHandler: We need to specify this handler in AWS lambda configuration later on.
package com.shunya.reverse
import org.springframework.cloud.function.adapter.aws.SpringBootRequestHandler
class Handler : SpringBootRequestHandler<NumberInput, NumberOutput>(LambdaApp::class.java)
Now lets define the actual Function that will take care of lambda request. This class will also act like a SpringBoot Application that will start the container.
package com.shunya.reverse
import com.fasterxml.jackson.databind.ObjectMapper
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.context.annotation.Bean
import java.util.function.Function
@SpringBootApplication
class LambdaApp {
@Bean
fun function(mathService: MathService, objectMapper: ObjectMapper): Function<NumberInput, NumberOutput?> {
return Function {
val output = NumberOutput()
output.result = mathService.reverse(it.input)
return@Function output
}
}
companion object {
@JvmStatic
fun main(args: Array<String>) {
SpringApplication.run(LambdaApp::class.java, *args)
}
}
}
The actual service that calculates the reverse of a number is defined following:
package com.shunya.reverse
import org.springframework.stereotype.Service
@Service
class MathService {
fun reverse(num: Long): Long {
var num = num
var sum: Long = 0
while (num != 0L) {
val lastDigit = num % 10
sum = sum * 10 + lastDigit
num /= 10
}
return sum
}
}
Now we are almost ready with our simple Spring Cloud Function that we can deploy to AWS Lambda.
Creating the build artifact
We are using aws specific dependencies (spring-cloud-function-adapter-aws
) in our project, which creates aws specific artifacts during the build:
dependencies {
compile 'com.amazonaws:aws-lambda-java-core:1.2.0'
compile 'com.amazonaws:aws-lambda-java-events:2.2.6'
compile 'com.amazonaws:aws-java-sdk-s3:1.11.557'
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
compile "org.jetbrains.kotlin:kotlin-reflect"
// compile 'org.springframework.cloud:spring-cloud-starter-function-web:2.1.0.RELEASE'
compile 'org.springframework.cloud:spring-cloud-function-adapter-aws:2.1.0.RELEASE'
testCompile 'org.springframework.boot:spring-boot-starter-test'
testCompile 'net.bytebuddy:byte-buddy:1.6.4'
testCompile 'org.objenesis:objenesis:1.2'
testCompile 'org.spockframework:spock-core:1.1-groovy-2.4'
testCompile 'org.spockframework:spock-spring:1.1-groovy-2.4'
}
Run the below command to create AWS specific package for this project:
$ ./gradlew clean build
spring-cloud-function-aws-example-1.0-SNAPSHOT-aws.jar
Now we have an artifact ready for the deployment on AWS Lambda.
Deploying the lambda function
We will use gradle-aws-plugin
to interact with AWS using gradle.
task deployFunction(type: AWSLambdaMigrateFunctionTask, dependsOn: [assemble, test]) {
functionName = "aws-lambda-kotlin-number-reverse"
runtime = com.amazonaws.services.lambda.model.Runtime.Java8
role = "arn:aws:iam::${aws.accountId}:role/lambdaDemoRole"
zipFile = shadowJar.archivePath
handler = "com.shunya.reverse.Handler"
memorySize = 512
timeout = 60
environment = [
SPRING_PROFILES_ACTIVE: "dev,aws",
MAIN_CLASS: "com.shunya.reverse.LambdaApp"
]
}
Invoke lambda using gradle plugin
We can use gradle-aws-plugin
to invoke lambda function. Firstly we need to create an input json file:
{
"input": 12345
}
task invokeFunction(type: AWSLambdaInvokeTask) {
// functionName = project.name
functionName = "aws-lambda-kotlin-number-reverse"
invocationType = InvocationType.RequestResponse
payload = file("src/test/resources/sample_request.json")
doLast {
println "Lambda function result: " + new String(invokeResult.payload.array())
}
}
$ ./gradlew invokeFunction
Lambda function result: {"result":54321}
Alternatively we can use manual approach to create and upload the Lambda function using AWS console.
Setting up AWS CLI
You will have to follow Amazon AWS official documentation to setup AWS CLI on your target platform:
Creating new Lambda Function
Login into AWS Console and select Lambda from the services section. Now create a new Java 8 lambda from scratch as shown in the below screen.
Click on the create function button.
On the next screen, select handler as the below text:
com.shunya.uppercase.handler.aws.ReverseFunctionHandler
Now upload the artifact created in previous step using upload button.
Create a new execution role from AWS Lambda template for this function.
Configure Test Input
Now we need to test our lambda using input:
Here we are providing the below json as the input to the lambda:
{
"input": 12345
}
Lambda Execution
As we can see, we get a reversed number as the response from our lambda function.
Invoking lambda using AWS CLI
We can use aws cli to invoke the lambda function, here is the syntax for the same:
$ aws lambda invoke --function-name number-reversal-java --payload '{"input": 23456}' output.txt
{
"StatusCode": 200,
"ExecutedVersion": "$LATEST"
}
If response is successful, we can check the output
$ cat output.txt
{ "result": 65432 }
That’s all for this article.
In future we can add other triggers to this lambda function, like API gateway/SQS etc.
Grab the source code from Github
Checkout source code for this project on Github:
Next
In the next article, we will invoke this lambda function from a Java Client using AWS SDK. You can use this approach to invoke AWS lambda from inside a java microservice or another aws lambda function.
Top articles in this category:
- Java AWS Lambda using Spring Cloud Function
- Invoke AWS Lambda from a Kotlin Client
- Invoking AWS Lambda from a Java Client
- Feign exception handling in Spring Cloud
- Spring Boot Sidecar
- Basic Auth Security in Spring Boot 2
- S3 File upload & download with AWS Java SDK v2