Agenda
- Running Micronaut on AWS Infrastructure
- Agorapulse Micronaut AWS SDK
- Summary
Micronaut AWS Support
Micronaut
Amazon Web Services
AWS Elastic Beanstalk
AWS Elastic Beanstalk is an easy-to-use service for deploying and scaling web applications and services developed with Java, .NET, PHP, Node.js, Python, Ruby, Go, and Docker on familiar servers such as Apache, Nginx, Passenger, and IIS.
AWS Elastic Beanstalk
AWS Elastic Beanstalk is an easy-to-use service for deploying and scaling web applications and services developed with Java, .NET, PHP, Node.js, Python, Ruby, Go, and Docker on familiar servers such as Apache, Nginx, Passenger, and IIS.
Micronaut Application
mn create-app beanstalk-app-java
cd beanstalk-app-java
mn create-controller env
@Controller("/env")
public class EnvController {
private final ApplicationContext applicationContext;
public EnvController(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Get("/")
public Set<String> index() {
return applicationContext.getEnvironment().getActiveNames();
}
}
Beanstalk + Shadow JAR
# src/main/resources/application.yml
micronaut:
application:
name: beanstalk-app-java
server:
port: 5000
plugins {
id "fi.evident.beanstalk" version "0.2.1"
}
version = '0.1-SNAPSHOT'
beanstalk {
s3Endpoint = "s3-eu-west-3.amazonaws.com"
beanstalkEndpoint = "elasticbeanstalk.eu-west-3.amazonaws.com"
deployments {
greach {
file = tasks.shadowJar
application = 'beanstalk-app-java'
environment = 'beanstalk-app-java-jar'
}
}
}
Micronaut Application
mn create-app beanstalk-app-java
cd beanstalk-app-java
mn create-controller env
@Controller("/env")
public class EnvController {
private final ApplicationContext applicationContext;
public EnvController(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Get("/")
public Set<String> index() {
return applicationContext.getEnvironment().getActiveNames();
}
}
Beanstalk + Archive + Procfile
# src/main/eb/env.config
option_settings:
aws:elasticbeanstalk:application:environment:
PORT: 8080 # application port
# src/main/eb/Procfile
web: java -jar application.jar
Beanstalk + Archive + Procfile
plugins {
id "fi.evident.beanstalk" version "0.2.1"
}
version = '0.1-SNAPSHOT'
task beanstalkArchive(type: Zip, dependsOn: jar) {
from 'src/main/eb'
from tasks.shadowJar
}
shadowJar {
archiveName = 'application.jar'
}
beanstalk {
s3Endpoint = "s3-eu-west-3.amazonaws.com"
beanstalkEndpoint = "elasticbeanstalk.eu-west-3.amazonaws.com"
deployments {
greach {
file = tasks.beanstalkArchive
application = 'beanstalk-app-java'
environment = 'beanstalk-app-java-env'
}
}
}
AWS Elastic Beanstalk
AWS Elastic Beanstalk is an easy-to-use service for deploying and scaling web applications and services developed with Java, .NET, PHP, Node.js, Python, Ruby, Go, and Docker on familiar servers such as Apache, Nginx, Passenger, and IIS.
Micronaut Application
mn create-app beanstalk-app
cd beanstalk-app
mn create-controller env
@Controller("/env")
public class EnvController {
private final ApplicationContext applicationContext;
public EnvController(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Get("/")
public Set<String> index() {
return applicationContext.getEnvironment().getActiveNames();
}
}
FROM adoptopenjdk/openjdk11-openj9:jdk-11.0.1.13-alpine-slim
EXPOSE 8080
COPY build/libs/*.jar beanstalk-app.jar
CMD java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -noverify ${JAVA_OPTS} -jar beanstalk-app.jar
plugins {
id "com.bmuschko.docker-remote-api" version "4.4.0"
id "com.patdouble.awsecr" version "0.5.1"
}
String registryHost = '1234567890.dkr.ecr.eu-west-3.amazonaws.com'
docker {
registryCredentials {
url = "https://$registryHost/"
}
}
task buildImage(type: com.bmuschko.gradle.docker.tasks.image.DockerBuildImage) {
dependsOn shadowJar
inputDir = file('.')
tags.add("$registryHost/beanstalk-app:latest")
}
task pushImage(type: com.bmuschko.gradle.docker.tasks.image.DockerPushImage) {
dependsOn buildImage
imageName = "$registryHost/beanstalk-app"
tag = 'latest'
}
Beanstalk + Docker
{
"AWSEBDockerrunVersion": "1",
"Image": {
"Name": "281741939716.dkr.ecr.eu-west-3.amazonaws.com/beanstalk-app:latest",
"Update": "true"
},
"Ports": [
{
"ContainerPort": "8080",
"HostPort": "80"
}
]
}
Beanstalk + Docker
// deployment
version = '0.1-SNAPSHOT'
// requires AmazonEC2ContainerRegistryReadOnly for aws-elasticbeanstalk-ec2-role
task buildArchive(type: Zip) {
from file('src/main/eb')
}
beanstalk {
s3Endpoint = "s3-eu-west-3.amazonaws.com"
beanstalkEndpoint = "elasticbeanstalk.eu-west-3.amazonaws.com"
deployments {
production {
file = tasks.buildArchive
application = 'beanstalk-app'
environment = "beanstalk-app"
}
}
}
Beanstalk + Docker
AWS Lambda
AWS Lambda lets you run code without provisioning or managing servers. You pay only for the compute time you consume - there is no charge when your code is not running.
AWS Lambda
Micronaut Functions
mn create-function lambda-function
cd lambda-function
@FunctionBean("lambda-function")
public class LambdaFunctionFunction implements Supplier<String> {
private final Environment environment;
public LambdaFunctionFunction(Environment environment) {
this.environment = environment;
}
@Override
public String get() {
return String.join(",", environment.getActiveNames());
}
}
Micronaut Functions
if(new File("${System.getProperty("user.home")}/.aws/credentials").exists()) {
task deploy(
type: jp.classmethod.aws.gradle.lambda.AWSLambdaMigrateFunctionTask,
dependsOn: shadowJar
) {
functionName = "lambda-function"
handler = "io.micronaut.function.aws.MicronautRequestStreamHandler"
role = "arn:aws:iam::${aws.accountId}:role/lambda_basic_execution"
runtime = com.amazonaws.services.lambda.model.Runtime.Java8
zipFile = shadowJar.archivePath
memorySize = 256
timeout = 60
}
}
MN Functions - Local Server
./gradlew shadowJar
java -jar build/libs/lambda-function-0.1.jar
curl http://localhost:8080/lambda-function
MN Functions - Client + Test
@FunctionClient
public interface LambdaFunctionClient {
@Named("lambda-function")
Single<String> index();
}
@MicronautTest
public class LambdaFunctionFunctionTest {
@Inject
LambdaFunctionClient client;
@Test
public void testFunction() throws Exception {
assertEquals(client.index().blockingGet(), "test");
}
}
MN Function + Gradle
./gradlew deploy
./gradlew invoke
task invoke(type: jp.classmethod.aws.gradle.lambda.AWSLambdaInvokeTask) {
functionName = "lambda-function"
invocationType = com.amazonaws.services.lambda.model.InvocationType.RequestResponse
payload = '{ }'
doLast {
println "Lambda function result: " + new String(invokeResult.payload.array(), "UTF-8")
}
}
MN FN + API Gateway
@FunctionBean("gateway-function")
public class GatewayFunctionFunction
implements Function<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {
private final ApplicationContext context;
private final ObjectMapper objectMapper;
public GatewayFunctionFunction(ApplicationContext context, ObjectMapper objectMapper) {
this.context = context;
this.objectMapper = objectMapper;
}
@Override
public APIGatewayProxyResponseEvent apply(APIGatewayProxyRequestEvent request) {
if ("GET".equalsIgnoreCase(request.getHttpMethod()) &&
"/env".equalsIgnoreCase(request.getPath())) {
try {
Set<String> names = context.getEnvironment().getActiveNames();
String body = objectMapper.writeValueAsString(names);
return new APIGatewayProxyResponseEvent().withBody(body);
} catch (JsonProcessingException e) {
return new APIGatewayProxyResponseEvent().withStatusCode(500);
}
}
return new APIGatewayProxyResponseEvent().withStatusCode(404);
}
}
MN FM + API Gateway (WS)
@FunctionBean("lambda-echo-java")
public class LambdaEchoJava implements Function<WebSocketRequest, WebSocketResponse> {
private final MessageSenderFactory factory;
private final TestTopicPublisher publisher;
public LambdaEchoJava(MessageSenderFactory factory, TestTopicPublisher publisher) {
this.factory = factory;
this.publisher = publisher;
}
@Override
public WebSocketResponse apply(WebSocketRequest event) {
MessageSender sender = factory.create(event.getRequestContext());
String connectionId = event.getRequestContext().getConnectionId();
switch (event.getRequestContext().getEventType()) {
case CONNECT:
case DISCONNECT:
break;
case MESSAGE:
String message = "[" + connectionId + "] " + event.getBody();
sender.send(connectionId, message);
publisher.publishMessage(connectionId, message);
break;
}
return WebSocketResponse.OK;
}
}
API Gatway + MN
API Gateway Support
mn create-app gateway-app --features aws-api-gateway
cd gateway-app
mn create-controller env
@Controller("/env")
public class EnvController {
private final ApplicationContext applicationContext;
public EnvController(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Get("/")
public Set<String> index() {
return applicationContext.getEnvironment().getActiveNames();
}
}
API Gateway + SAM
./gradlew buildZip
npm install -g aws-sam-local
sam local start-api --template sam.yaml
curl http://127.0.0.1:3000/env
aws cloudformation package --template-file sam.yaml --output-template-file output-sam.yaml \
--s3-bucket <YOUR S3 BUCKET NAME>
aws cloudformation deploy --template-file output-sam.yaml --stack-name ServerlessMicronautApi \
--capabilities CAPABILITY_IAM
aws cloudformation describe-stacks --stack-name ServerlessMicronautApi
API Gateway + GraalVM
mn create-app gateway-graal-app --features aws-api-gateway-graal
cd gateway-graal-app
docker build . -t gateway-graal-app
mkdir build
docker run --rm --entrypoint cat gateway-graal-app \
/home/application/function.zip > build/function.zip
aws lambda create-function --function-name gateway-graal-app \
--zip-file fileb://build/function.zip --handler function.handler --runtime provided \
--role arn:aws:iam::881337894647:role/lambda_basic_execution
- Alexa
- Route 53 Service Discovery
- Parameter Store
More ...
Parameter Store
Parameter Store
@Controller("/conference")
public class ConferenceController {
private final String name;
public ConferenceController(@Value("${conference.name}") String name) {
this.name = name;
}
@Get("/")
public String index() {
return name;
}
}
Agorapulse Micronaut AWS SDK
Agorapulse
Micronaut AWS SDK
- Reworked Grails Plugins
- Aligned with Micronaut Philosophy
- Client, Listener & Service Introductions
- Java Friendly
- Easy Testable
Simple Email Service
Amazon Simple Email Service (Amazon SES) is a cloud-based email sending service designed to help digital marketers and application developers send marketing, notification, and transactional emails. It is a reliable, cost-effective service for businesses of all sizes that use email to keep in contact with their customers.
Simple Email Service
@Test
public void testSendEmail() throws IOException {
when(simpleEmailService.sendRawEmail(Mockito.any()))
.thenReturn(new SendRawEmailResult().withMessageId("foobar"));
File file = tmp.newFile("test.pdf");
Files.write(file.toPath(), Collections.singletonList("not a real PDF"));
String filepath = file.getCanonicalPath();
EmailDeliveryStatus status = service.send(e ->
e.subject("Hi Paul")
.from("subscribe@groovycalamari.com")
.to("me@sergiodelamo.com")
.htmlBody("<p>This is an example body</p>")
.attachment(a ->
a.filepath(filepath)
.filename("test.pdf")
.mimeType("application/pdf")
.description("An example pdf")
)
);
Assert.assertEquals(EmailDeliveryStatus.STATUS_DELIVERED, status);
}
Simple Email Service
void "send email"() {
given:
File file = tmp.newFile('test.pdf')
file.text = 'not a real PDF'
String thePath = file.canonicalPath
when:
EmailDeliveryStatus status = service.send {
subject 'Hi Paul'
from 'subscribe@groovycalamari.com'
to 'me@sergiodelamo.com'
htmlBody '<p>This is an example body</p>'
attachment {
filepath thePath
filename 'test.pdf'
mimeType 'application/pdf'
description 'An example pdf'
}
}
then:
status == EmailDeliveryStatus.STATUS_DELIVERED
simpleEmailService.sendRawEmail(_) >> { SendRawEmailRequest request ->
return new SendRawEmailResult().withMessageId('foobar')
}
}
Simple Storage Service
Amazon Simple Storage Service (Amazon S3) is an object storage service that offers industry-leading scalability, data availability, security, and performance. This means customers of all sizes and industries can use it to store and protect any amount of data for a range of use cases, such as websites, mobile applications, backup and restore, archive, enterprise applications, IoT devices, and big data analytics.
Simple Storage Service
// create bucket
service.createBucket(MY_BUCKET);
assertTrue(service.listBucketNames().contains(MY_BUCKET));
// upload file
File sampleContent = createFileWithSampleContent();
service.storeFile(TEXT_FILE_PATH, sampleContent);
assertTrue(service.exists(TEXT_FILE_PATH));
Flowable<S3ObjectSummary> summaries = service.listObjectSummaries("foo");
assertEquals(Long.valueOf(1L), summaries.count().blockingGet());
// generate downloadable URL
String url = service.generatePresignedUrl(KEY, TOMORROW);
assertEquals(SAMPLE_CONTENT, download(url));
// download file
File dir = tmp.newFolder();
File file = new File(dir, "bar.baz");
service.getFile(KEY, file);
assertTrue(file.exists());
assertEquals(SAMPLE_CONTENT, new String(Files.readAllBytes(Paths.get(file.toURI()))));
// delete file
service.deleteFile(TEXT_FILE_PATH);
assertFalse(service.exists(TEXT_FILE_PATH));
Queues & Topics & Streams
Simple Queue Service
Amazon Simple Queue Service (SQS) is a fully managed message queuing service that enables you to decouple and scale microservices, distributed systems, and serverless applications. SQS eliminates the complexity and overhead associated with managing and operating message oriented middleware, and empowers developers to focus on differentiating work. Using SQS, you can send, store, and receive messages between software components at any volume, without losing messages or requiring other services to be available.
Simple Notification Service
Amazon Simple Notification Service (SNS) is a highly available, durable, secure, fully managed pub/sub messaging service that enables you to decouple microservices, distributed systems, and serverless applications. Amazon SNS provides topics for high-throughput, push-based, many-to-many messaging. Using Amazon SNS topics, your publisher systems can fan out messages to a large number of subscriber endpoints for parallel processing, including Amazon SQS queues, AWS Lambda functions, and HTTP/S webhooks. Additionally, SNS can be used to fan out notifications to end users using mobile push, SMS, and email.
Amazon Kinesis
Amazon Kinesis makes it easy to collect, process, and analyze real-time, streaming data so you can get timely insights and react quickly to new information. Amazon Kinesis offers key capabilities to cost-effectively process streaming data at any scale, along with the flexibility to choose the tools that best suit the requirements of your application. With Amazon Kinesis, you can ingest real-time data such as video, audio, application logs, website clickstreams, and IoT telemetry data for machine learning, analytics, and other applications.
SQS vs SNS vs Kinesis
SQS
- Queues
- Single recipient
- FIFO Available
- Pull or Lambda
SNS
- Topics
- Multiple recipients
- Mobile Push
- SMS
- Emails
- HTTP/HTTPS
Kinesis
- Data streams
- Multiple recipients
- Realtime data
- Data replay
- Shard mgmt
Simple Queue Service
Amazon Simple Queue Service (SQS) is a fully managed message queuing service that enables you to decouple and scale microservices, distributed systems, and serverless applications. SQS eliminates the complexity and overhead associated with managing and operating message oriented middleware, and empowers developers to focus on differentiating work. Using SQS, you can send, store, and receive messages between software components at any volume, without losing messages or requiring other services to be available.
Simple Queue Service
@QueueClient
interface DefaultClient {
@Queue(value = "OtherQueue", group = "SomeGroup")
String sendMessageToQueue(String message);
String sendMessage(Pogo message);
String sendMessage(byte[] record);
String sendMessage(String record);
String sendMessage(String record, int delay);
String sendMessage(String record, String group);
String sendMessage(String record, int delay, String group);
void deleteMessage(String messageId);
String OTHER_QUEUE = "OtherQueue";
}
Simple Queue Service
@Testcontainers
@RestoreSystemProperties
class SimpleQueueServiceSpec extends Specification {
@Shared LocalStackContainer localstack = new LocalStackContainer('0.8.10')
.withServices(SQS)
@AutoCleanup ApplicationContext context
SimpleQueueService service
void setup() {
System.setProperty('com.amazonaws.sdk.disableCbor', 'true')
AmazonSQS sqs = AmazonSQSClient
.builder()
.withEndpointConfiguration(localstack.getEndpointConfiguration(SQS))
.withCredentials(localstack.defaultCredentialsProvider)
.build()
context = ApplicationContext.build('aws.sqs.queue': TEST_QUEUE).build()
context.registerSingleton(AmazonSQS, sqs)
context.start()
service = context.getBean(SimpleQueueService)
}
// tests
}
Simple Notification Service
Amazon Simple Notification Service (SNS) is a highly available, durable, secure, fully managed pub/sub messaging service that enables you to decouple microservices, distributed systems, and serverless applications. Amazon SNS provides topics for high-throughput, push-based, many-to-many messaging. Using Amazon SNS topics, your publisher systems can fan out messages to a large number of subscriber endpoints for parallel processing, including Amazon SQS queues, AWS Lambda functions, and HTTP/S webhooks. Additionally, SNS can be used to fan out notifications to end users using mobile push, SMS, and email.
Simple Notification Service
@NotificationClient
interface DefaultClient {
String OTHER_TOPIC = "OtherTopic";
@Topic("OtherTopic") String publishMessageToDifferentTopic(Pogo pogo);
String publishMessage(Pogo message);
String publishMessage(String subject, Pogo message);
String publishMessage(String message);
String publishMessage(String subject, String message);
String sendSMS(String phoneNumber, String message);
String sendSms(String phoneNumber, String message, Map attributes);
}
Simple Notification Service
String appArn = service.createAndroidApplication("my-app", API_KEY);
String endpoint = service.registerAndroidDevice(appArn, DEVICE_TOKEN, DATA);
Map<String, String> notif = new LinkedHashMap<>();
notif.put("badge", "9");
notif.put("data", "{\"foo\": \"some bar\"}");
notif.put("title", "Some Title");
String msgId = service.sendAndroidAppNotification(endpoint, notif, "Welcome");
service.validateAndroidDevice(appArn, endpoint, DEVICE_TOKEN, DATA);
service.unregisterDevice(endpoint);
Amazon Kinesis
Amazon Kinesis makes it easy to collect, process, and analyze real-time, streaming data so you can get timely insights and react quickly to new information. Amazon Kinesis offers key capabilities to cost-effectively process streaming data at any scale, along with the flexibility to choose the tools that best suit the requirements of your application. With Amazon Kinesis, you can ingest real-time data such as video, audio, application logs, website clickstreams, and IoT telemetry data for machine learning, analytics, and other applications.
Amazon Kinesis
@KinesisClient
interface DefaultClient {
void putRecordString(String record);
PutRecordResult putRecord(String partitionKey, String record);
void putRecordAnno(@PartitionKey String id, String record);
void putRecord(String partitionKey, String record, String sequenceNumber);
void putRecordAnno(
@PartitionKey String id,
String record,
@SequenceNumber String sqn
);
void putRecordAnnoNumbers(
@PartitionKey Long id,
String record,
@SequenceNumber int sequenceNumber
);
}
Amazon Kinesis
@KinesisClient
interface DefaultClient {
void putRecordBytes(byte[] record);
void putRecordDataByteArray(@PartitionKey String id, byte[] value);
PutRecordsResult putRecords(Iterable<PutRecordsRequestEntry> entries);
PutRecordsResult putRecords(PutRecordsRequestEntry... entries);
PutRecordsResult putRecord(PutRecordsRequestEntry entry);
}
Amazon Kinesis
@KinesisClient
interface DefaultClient {
void putRecordObject(Pogo pogo);
PutRecordsResult putRecordObjects(Pogo... pogo);
PutRecordsResult putRecordObjects(Iterable<Pogo> pogo);
void putRecordDataObject(@PartitionKey String id, Pogo value);
}
Amazon Kinesis
@Singleton
public class KinesisListenerTester {
@KinesisListener
public void listenString(String string) {
String message = "EXECUTED: listenString(" + string + ")";
logExecution(message);
}
@KinesisListener
public void listenRecord(Record record) {
logExecution("EXECUTED: listenRecord(" + record + ")");
}
@KinesisListener
public void listenObject(MyEvent event) {
logExecution("EXECUTED: listenObject(" + event + ")");
}
@KinesisListener
public void listenPogoRecord(Pogo event) {
logExecution("EXECUTED: listenPogoRecord(" + event + ")");
}
}
Amazon DynamoDB
Amazon DynamoDB is a key-value and document database that delivers single-digit millisecond performance at any scale. It's a fully managed, multiregion, multimaster database with built-in security, backup and restore, and in-memory caching for internet-scale applications. DynamoDB can handle more than 10 trillion requests per day and support peaks of more than 20 million requests per second.
Amazon DynamoDB
@DynamoDBTable(tableName = "entity")
public class DynamoDBEntity {
public static final String DATE_INDEX = "date";
public static final String RANGE_INDEX = "rangeIndex";
public static final String GLOBAL_INDEX = "globalIndex";
@DynamoDBHashKey
String parentId;
@DynamoDBRangeKey
String id;
@DynamoDBIndexRangeKey(localSecondaryIndexName = RANGE_INDEX)
String rangeIndex;
@DynamoDBIndexRangeKey(localSecondaryIndexName = DATE_INDEX)
Date date;
Integer number = 0;
// boilerplate
}
Amazon DynamoDB
@Service(DynamoDBEntity)
interface DynamoDBItemDBService {
DynamoDBEntity get(String hash, String rangeKey)
List<DynamoDBEntity> getAll(String hash, List<String> rangeKeys)
List<DynamoDBEntity> getAll(String hash, String... rangeKeys)
DynamoDBEntity save(DynamoDBEntity entity)
List<DynamoDBEntity> saveAll(DynamoDBEntity... entities)
List<DynamoDBEntity> saveAll(Iterable<DynamoDBEntity> entities)
int count(String hashKey)
int count(String hashKey, String rangeKey)
}
Amazon DynamoDB
@Service(DynamoDBEntity)
interface DynamoDBItemDBService {
@Query({
query(DynamoDBEntity) {
hash hashKey
range {
eq DynamoDBEntity.RANGE_INDEX, rangeKey
}
only {
rangeIndex
}
}
})
Flowable<DynamoDBEntity> queryByRangeIndex(String hashKey, String rangeKey)
@Query({
query(DynamoDBEntity) {
hash hashKey
range {
eq DynamoDBEntity.RANGE_INDEX, rangeKey
}
}
})
int countByRangeIndex(String hashKey, String rangeKey)
}
Amazon DynamoDB
@Service(DynamoDBEntity.class)
public interface DynamoDBEntityService {
class EqRangeScan implements Function<Map<String, Object>, DetachedScan> {
public DetachedScan apply(Map<String, Object> arguments) {
return Builders.scan(DynamoDBEntity.class)
.filter(f -> f.eq(DynamoDBEntity.RANGE_INDEX, arguments.get("foo")));
}
}
@Scan(EqRangeScan.class)
Flowable<DynamoDBEntity> scanAllByRangeIndex(String foo);
}
Amazon DynamoDB
@Service(DynamoDBEntity)
interface DynamoDBItemDBService {
@Scan({
scan(DynamoDBEntity) {
filter {
eq DynamoDBEntity.RANGE_INDEX, foo
}
}
})
Flowable<DynamoDBEntity> scanAllByRangeIndex(String foo)
}
Amazon DynamoDB
@Service(DynamoDBEntity)
interface DynamoDBItemDBService {
@Update({
update(DynamoDBEntity) {
hash hashKey
range rangeKey
add 'number', 1
returnUpdatedNew { number }
}
})
Number increment(String hashKey, String rangeKey)
@Update({
update(DynamoDBEntity) {
hash hashKey
range rangeKey
add 'number', -1
returnUpdatedNew { number }
}
})
Number decrement(String hashKey, String rangeKey)
}
Summary
- Running Micronaut on AWS Infrastructure
- Elastic Beanstalk
- Java
- Docker
- Lambda
- Functions & Trigger Handlers
- API Gateway Integrations
- Elastic Beanstalk
- Agorapulse Micronaut AWS SDK
- Emails with SES
- File uploads with S3
- Messaging with SQS, SNS and Kinesis
- Persistence with DynamoDB
Thank You
AWS + MN = BFF
By musketyr
AWS + MN = BFF
- 2,720