AWS + MN = BFF

Vladimír Oraný

Test Facilitator @ Agorapulse

@musketyr

 

http://micronaut.io/

 

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
  • Agorapulse Micronaut AWS SDK
    • Emails with SES
    • File uploads with S3
    • Messaging with SQS, SNS and Kinesis
    • Persistence with DynamoDB

Thank You

Made with Slides.com