Overview


Spring Cloud Hystrix Project was built as a wrapper on top of the Netflix Hystrix library. Since then, It has been adopted by many enterprises and developers to implement the Circuit Breaker pattern.
In November 2018 when Netflix announced that they are putting this project into maintenance mode, it prompted Spring Cloud to announce the same. Since then, no further enhancements are happening in this Netflix library. In SpringOne 2019, Spring announced that Hystrix Dashboard will be removed from Spring Cloud 3.1 version which makes it officially dead.
As the Circuit Breaker pattern has been advertised so heavily, many developers have either used it or want to use it, and now need a replacement. Resilience4j has been introduced to fulfill this gap and provide a migration path for Hystrix users.

Resilience4j

Resilience4j has been inspired by Netflix Hystrix but is designed for Java 8 and functional programming. It is lightweight compared to Hystrix as it has the Vavr library as its only dependency. Netflix Hystrix, by contrast, has a dependency on Archaius which has several other external library dependencies such as Guava and Apache Commons.
A new library always has one advantage over a previous library - it can learn from the mistakes of its predecessor. Resilience4j also comes with many new features:

CircuitBreaker

When a service invokes another service, there is always a possibility that it may be down or having high latency. This may lead to exhaustion of the threads as they might be waiting for other requests to complete. The CircuitBreaker pattern functions in a similar fashion to an electrical Circuit Breaker:
  • When a number of consecutive failures cross the defined threshold, the Circuit Breaker trips.
  • For the duration of the timeout period, all requests invoking the remote service will fail immediately.
  • After the timeout expires the Circuit Breaker allows a limited number of test requests to pass through.
  • If those requests succeed the Circuit Breaker resumes normal operation.
  • Otherwise, if there is a failure the timeout period begins again.

RateLimiter

Rate Limiting pattern ensures that a service accepts only a defined maximum number of requests during a window. This ensures that underline resources are used as per their limits and don't exhaust.

Retry

Retry pattern enables an application to handle transient failures while calling to external services. It ensures retrying operations on external resources a set number of times. If it doesn't succeed after all the retry attempts, it should fail and response should be handled gracefully by the application.

Bulkhead

Bulkhead ensures the failure in one part of the system doesn't cause the whole system down. It controls the number of concurrent calls a component can take. This way, the number of resources waiting for the response from that component is limited. There are two types of bulkhead implementation:
  • The semaphore isolation approach limits the number of concurrent requests to the service. It rejects requests immediately once the limit is hit.
  • The thread pool isolation approach uses a thread pool to separate the service from the caller and contain it to a subset of system resources.
The thread pool approach also provides a waiting queue, rejecting requests only when both the pool and queue are full. Thread pool management adds some overhead, which slightly reduces performance compared to using a semaphore, but allows hanging threads to time out.             

Build a Spring Boot Application with Resilience4j

In this article, we will build 2 services - Book Management and Library Management.
In this system, Library Management calls Book Management. We will need to bring Book Management service up and down to simulate different scenarios for the CircuitBreaker, RateLimit, Retry and Bulkhead features.

Prerequisites

  1. JDK 8
  2. Spring Boot 2.1.x
  3. resilience4j 1.1.x (latest version of resilience4j is 1.3 but resilience4j-spring-boot2 has latest version 1.1.x only)
  4. IDE like Eclipse, VSC or intelliJ (prefer to have VSC as it is very lightweight. I like it more compared to Eclipse and intelliJ)
  5. Gradle
  6. NewRelic APM tool ( you can use Prometheus with Grafana also)

Book Management service
  1. Gradle Dependency   
This service is a simple REST-based API and needs standard spring-boot starter jars for web and test dependencies. We will also enable swagger to test the API:
dependencies {
    //REST
    implementation 'org.springframework.boot:spring-boot-starter-web'
    //swagger
    compile group: 'io.springfox', name: 'springfox-swagger2', version: '2.9.2'
    implementation group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.9.2'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
     2. Configuration
The configuration has only a single port as detailed configuration:
server:
    port: 8083

  1. Service Implementation
It has two methods addBook and retrieveBookList. Just for demo purposes, we are using an ArrayList object to store the book information:
@Service
public class BookServiceImpl implements BookService {

    List<Book> bookList = new ArrayList<>();

    @Override
    public String addBook(Book book) {
        String message  =   "";
        boolean status  =   bookList.add(book);
        if(status){
            message=    "Book is added successfully to the library.";
        }
        else{
             message=    "Book could not be added in library due to some technical issue. Please try later!";
        }
        return message;
    }

    @Override
    public List<Book> retrieveBookList() {
        return bookList;
    }
}

  1. Controller
Rest Controller has exposed two APIs - one is POST for adding book and the other is GET for retrieving book details:
@RestController
@RequestMapping("/books")
public class BookController {

    @Autowired
    private BookService bookService  ;

    @PostMapping
    public String addBook(@RequestBody Book book){
        return bookService.addBook(book);
    }

    @GetMapping
    public List<Book> retrieveBookList(){
        return bookService.retrieveBookList();
    }
}
  1. Test Book Management Service
Build and start the application by using the below commands:
//build application
gradlew build

//start application
java -jar build/libs/bookmanangement-0.0.1-SNAPSHOT.jar

//endpoint url
http://localhost:8083/books
Now we can test the application using Swagger UI - http://localhost:8083/swagger-ui.html
Ensure the service is up and running before moving to build the Library Management service.

Library Management service

In this service, we will be enabling all of the Resilience4j features.
  1. Gradle Dependency   
This service is also a simple REST-based API and also needs standard spring-boot starter jars for web and test dependencies. To enable CircuitBreaker and other resilience4j features in the API, we have added a couple of other dependencies like - resilience4j-spring-boot2, spring-boot-starter-actuator, spring-boot-starter-aop. We need to also add micrometer dependencies (micrometer-registry-prometheus, micrometer-registry-new-relic) to enable the metrics for monitoring. And lastly, we enable swagger to test the API:
dependencies {
    
    compile 'org.springframework.boot:spring-boot-starter-web'
    
    //resilience
    compile "io.github.resilience4j:resilience4j-spring-boot2:${resilience4jVersion}"
    compile 'org.springframework.boot:spring-boot-starter-actuator'
    compile('org.springframework.boot:spring-boot-starter-aop')
 
    //swagger
    compile group: 'io.springfox', name: 'springfox-swagger2', version: '2.9.2'
    implementation group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.9.2'

    // monitoring
        compile "io.micrometer:micrometer-registry-prometheus:${resilience4jVersion}"
      compile 'io.micrometer:micrometer-registry-new-relic:latest.release'

    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
  1. Configuration
Here, we need to do a couple of configurations -
-  By default CircuitBreaker and RateLimiter actuator APIs are disabled in spring 2.1.x. We need to enable them using management properties. Refer those properties in the source code link shared at the end of the article. We also need to add the following other properties:
-  Configure NewRelic Insight API key and account id
management:
   metrics:
    export:
      newrelic:
        api-key: xxxxxxxxxxxxxxxxxxxxx
        account-id: xxxxx
        step: 1m
-  Configure resilience4j CircuitBreaker properties for "add" and "get" service APIs.
 resilience4j.circuitbreaker:
  instances:
    add:
      registerHealthIndicator: true
      ringBufferSizeInClosedState: 5
      ringBufferSizeInHalfOpenState: 3
      waitDurationInOpenState: 10s
      failureRateThreshold: 50
      recordExceptions:
        - org.springframework.web.client.HttpServerErrorException
        - java.io.IOException
        - java.util.concurrent.TimeoutException
        - org.springframework.web.client.ResourceAccessException
        - org.springframework.web.client.HttpClientErrorException
      ignoreExceptions:
-  Configure resilience4j RateLimiter properties for "add" service API.
resilience4j.ratelimiter:
  instances:
    add:
      limitForPeriod: 5
      limitRefreshPeriod: 100000
          timeoutDuration: 1000ms
-  Configure resilience4j Retry properties for "get" service API.
resilience4j.retry:
  instances:
    get:
      maxRetryAttempts: 3
      waitDuration: 5000
-  Configure resilience4j Bulkhead properties for "get" service API.
resilience4j.bulkhead:
  instances:
    get:
      maxConcurrentCall: 10
      maxWaitDuration: 10ms
Now, we will be creating a LibraryConfig class to define a bean for RestTemplate to make a call to Book Management service. We have also hardcoded the endpoint URL of Book Management service here. Not a good idea for a production-like application but the purpose of this demo is only to showcase the resilience4j features. For a production app, we may want to use the service-discovery service.
@Configuration
public class LibraryConfig {
    Logger logger = LoggerFactory.getLogger(LibrarymanagementServiceImpl.class);
    private static final String baseUrl = "https://bookmanagement-service.apps.np.sdppcf.com";

    @Bean
    RestTemplate restTemplate(RestTemplateBuilder builder) {
        UriTemplateHandler uriTemplateHandler = new RootUriTemplateHandler(baseUrl);
        return builder
                .uriTemplateHandler(uriTemplateHandler)
                .build();
   }
 
}
  1. Service
Service Implementation has methods which are wrapped with @CircuitBreaker,@RateLimiter, @Retry  and @Bulkhead annotations These all annotation supports fallbackMethod attribute and redirect the call to the fallback functions in case of failures observed by each pattern. We would need to define the implementation of these fallback methods:
This method has been enabled by CircuitBreaker annotation. So if /books endpoint fails to return the response, it is going to call fallbackForaddBook() method.
    @Override
    @CircuitBreaker(name = "add", fallbackMethod = "fallbackForaddBook")
    public String addBook(Book book){
        logger.error("Inside addbook call book service. ");
        String response = restTemplate.postForObject("/books", book, String.class);
        return response;
    }
This method has been enabled by RateLimiter annotation. If the /books endpoint is going to reach the threshold defined in a configuration defined above, it will call fallbackForRatelimitBook() method.
    @Override
    @RateLimiter(name = "add", fallbackMethod = "fallbackForRatelimitBook")
    public String addBookwithRateLimit(Book book){
        String response = restTemplate.postForObject("/books", book, String.class);
        logger.error("Inside addbook, cause ");
        return response;
    }
This method has been enabled by Retry annotation. If the /books endpoint is going to reach the threshold defined in a configuration defined above, it will call fallbackRetry() method.
    @Override
    @Retry(name = "get", fallbackMethod = "fallbackRetry")
    public List<Book> getBookList(){
        return restTemplate.getForObject("/books", List.class);
    }
This method has been enabled by Bulkhead annotation. If the /books endpoint is going to reach the threshold defined in a configuration defined above, it will call fallbackBulkhead() method.
    @Override
    @Bulkhead(name = "get", type = Bulkhead.Type.SEMAPHORE, fallbackMethod = "fallbackBulkhead")
    public List<Book> getBookListBulkhead() {
        logger.error("Inside getBookList bulk head");
        try {
            Thread.sleep(100000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return restTemplate.getForObject("/books", List.class);
    }
Once the service layer is set up, we need to expose the corresponding REST APIs for each of the methods so that we can test them. For that, we need to create the RestController class.
  1. Controller
Rest Controller has exposed 4 APIs -
   - First one is a POST for adding a book
   - Second is again a POST for adding book but this will be used to demo Rate-Limit feature.
   - The third one is GET for retrieving book details.
   - Forth one is GET API for retrieving book details but enabled with bulkhead feature.
@RestController
@RequestMapping("/library")
public class LibrarymanagementController {

    @Autowired
    private LibrarymanagementService librarymanagementService;
    @PostMapping
    public String addBook(@RequestBody Book book){
        return librarymanagementService.addBook(book);
    }

    @PostMapping ("/ratelimit")
    public String addBookwithRateLimit(@RequestBody Book book){
        return librarymanagementService.addBookwithRateLimit(book);
    }

    @GetMapping
    public List<Book> getSellersList() {
        return librarymanagementService.getBookList();
    }
    @GetMapping ("/bulkhead")
    public List<Book> getSellersListBulkhead() {
        return librarymanagementService.getBookListBulkhead();
    }
}
Now, the code is ready. We have to build and bring it up and running.
  1. Build and Test Library Management Service
Build and start the application by using the below commands:
//Build
gradlew build

//Start the application
java -jar build/libs/librarymanangement-0.0.1-SNAPSHOT.jar

//Endpoint Url
http://localhost:8084/library
Now we can test the application using Swagger UI - http://localhost:8084/swagger-ui.html

Run Test Scenarios for CircuitBreaker RateLimiter Retry and Bulkhead

CircuitBreaker - Circuit Breaker has been applied to addBook API. To test if it's working, we will stop the Book Management service.
  • First, observe the health of the application by hitting http://localhost:8084/actuator/health URL.
  • Now stop the Book Management service and hit addBook API of Library Management service using swagger UI
At the first step, It should show the circuit breaker state as "CLOSED". This is Prometheus metrics which we enabled through the micrometer dependency.
After we execute the second step, it will start failing and redirecting to the fallback method.
Once it crosses the threshold, which in this case is 5, it will trip the circuit. And, each call after that will directly go to the fallback method without making an attempt to hit Book Management service. (You can verify this by going to logs and observe the logger statement. Now, we can observe the /health endpoint showing CircuitBreaker state as "OPEN".
{
    "status": "DOWN",
    "details": {
        "circuitBreakers": {
            "status": "DOWN",
            "details": {
                "add": {
                    "status": "DOWN",
                    "details": {
                        "failureRate": "100.0%",
                        "failureRateThreshold": "50.0%",
                        "slowCallRate": "-1.0%",
                        "slowCallRateThreshold": "100.0%",
                        "bufferedCalls": 5,
                        "slowCalls": 0,
                        "slowFailedCalls": 0,
                        "failedCalls": 5,
                        "notPermittedCalls": 0,
                        "state": "OPEN"
                    }                        
                }
            }
        }
    }
}
We have deployed the same code to PCF (Pivotal Cloud Foundry) so that we can integrate it with NewRelic to create the dashboard for this metric. We have used micrometer-registry-new-relic dependency for that purpose.

Image 2 - NewRelic Insight CircuitBreaker Closed Graph
Rate Limiter - We have created separate API (http://localhost:8084/library/ratelimit) having the same addBook functionality but enabled with Rate-Limit feature. In this case, we would need Book Management Service up and running. With the current configuration for the rate limit, we can have a maximum of 5 requests per 10 seconds.
Once we hit the API for 5 times within 10 seconds of time, it will reach the threshold and get throttled. To avoid throttling, it will go to the fallback method and respond based on the logic implemented there. Below graph shows that it has reached the threshold limit 3 times in the last hour:

Retry - Retry feature enables the API to retry the failed transaction again and again until the maximum configured value. If it gets succeeded, it will refresh the count to zero. If it reaches the threshold, it will redirect it to the fallback method defined and execute accordingly. To emulate this, hit the GET API (http://localhost:8084/library) when Book Management service is down. We will observe in logs that it is printing the response from fallback method implementation.
Bulkhead - In this example, we have implemented the Semaphore implementation of the bulkhead. To emulate concurrent calls, we have used Jmeter and set up the 30 user calls in the Thread group.
We will be hitting GET API () enabled with @Bulkhead annotation. We have also put some sleep time in this API so that we can hit the limit of concurrent execution. We can observe in the logs that it is going to the fallback method for some of the thread calls. Below is the graph for the available concurrent calls for an API:
Summary
In this article, we saw various features that are now a must in a microservice architecture, which can be implemented using one single library resilience4j. Using Prometheus with Grafana or NewRelic, we can create dashboards around these metrics and increase the stability of the systems.
As usual, the code can be found over Github -  spring-boot-resilience4j
Rajesh Bhojwani January 01, 2020
Read more ...

External Blogs

Other than writing on my own website, I do write my articles on Dzone, Medium, InfoQ, and other professional websites:

DZone Blogs -  20+ Articles with ~1Million overall views


Medium Blogs - 4 Articles


InfoQ Blogs  - It's the beginning phase


Lumigo Blogs - All Serverless latest blogs can be found here.



Rajesh Bhojwani December 23, 2019
Read more ...

Youtube Videos

In addition to writing blogs, I enjoy creating video blogs on youtube.
So far, I have created the following videos:

PCF 2.4 feature- Service Instance Sharing in PCF

This video explains the new feature of PCF 2.3 and 2.4 which allows you to share the PCF marketplace service instance across multiple Orgs/Spaces.

Running Batch Application in PCF

In this video, we will see how to build a Spring Batch or Spring Cloud Task application and run it on PCF either manually or through PCF Scheduler.

AWS Step Functions Lesson Learned

This video talks about what is Step Functions, what are the Benefits, limitation and Best practices around it.


This video talks about - 1. Basics of Serverless Application 2. How AWS Lambda can be used to build Serverless applications. 3. Common Problems developer face while designing Lambda 4. What are the best practices you can follow to mitigate common problems


AWS Lambda Destinations vs Step Functions

This video talks through what is Lambda Destinations feature introduced in AWS 2019 reinvent and how it can replace some of the workloads being served by step functions.


Rajesh Bhojwani December 23, 2019
Read more ...

Rajesh Bhojwani December 23, 2019
Read more ...

Rajesh Bhojwani December 23, 2019
Read more ...
Introduction

AWS has recently launched the first time ever a Serverless Event Bus AWS EventBridge. Some say it is the extension of CloudWatch Events, others say it is providing the same features what SNS service offers.

In this article, we will talk through what exactly AWS EventBridge service is, where it can be used. Also, how it is different from CloudWatch Events, SNS and Kinesis services.

What is AWS EventBridge Service

EventBridge is bringing together your own (e.g. legacy) applications, SaaS (Software-as-a-Service) and AWS Services. It can stream real-time data from various event sources like Pagerduty, Datadog, and routes to various targets (AWS services) like SQS, Lambda, and Others. 
It supports 10 SaaS application partners and 90+ AWS Services as event sources. It supports 17 AWS Services as Targets and this list will grow over the years.

In simple terms, AWS EventBridge is an event bus which supports publish/subscribe model. Applications can publish events to it and it can fan-out to multiple target services. Now, the basic question would arise; what is new in it. The Event Bus is an old concept and AWS itself is providing that functionality through CloudWatch Events. 

Genesis of EventBridge

EventBridge is brought mainly to address the problems of SaaS platform integration with AWS services. In the current Cloud world, SaaS platforms like CRM, Identity providers have become key partners. They generate a large amount of data and need to pass it to AWS platforms for business processing. Before EventBridge, there were majorly two solutions to send these event data to AWS:

Polling

In this solution, we generally set up a Cron job or CloudWatch Scheduler to go out and call the SaaS APIs. It will check if any change in data and then pull the data. Polling frequency can be minutes to hours depending on the use case and SaaS platform capacity to bear the load. Look at the typical flow as below:



This solution looks simple but it brings two major issues:

  • Data Freshness issue - Scheduler will be calling the API may be every few minutes or an hour. So, it will not give real-time data. There will always be a gap which might not work in some of the business scenarios. 
  • Costing and Performance issues - To alleviate the data freshness issue, if we reduce the interval of polling, it will increase the cost as calls will be increased. Also, more resources will be consumed at the SaaS platform. This may cause throttle and slow performance issues.
So, the overall recommendation is to avoid Polling mechanism if you can.

SaaS Webhooks

This is another technique which eliminates the data freshness issue. Here, we find out an Http endpoint of the AWS hosted application which SaaS platform can call to send the events data. SaaS platform will set up the webhooks and send real-time data when records change. Look at a typical use case below:


In this flow, we still need to manage the public endpoint of the application for handling security/DDoS attacks. It will also require Authentication handling. In AWS, mostly it is done through with API Gateway or WAF/ALB option. We would need to write the code as well to handle the events.

So, looking at these shortcomings, AWS came up with EventBridge service which enables SaaS platforms to create Native Event source at AWS side and have a secure connection just by sharing Account Id and region with platforms. It not only solves the issue of real-time data processing but also takes care of event ingestion and delivery, security, authorization, and error handling for you.



Source: https://d1.awsstatic.com/product-marketing/EventBridge/product-page-diagram-EventBridge_How-it-works_V2@2x.1a889967415e66231d0bb0bbfee14337d3fa5aa8.png

Now, let us talk about what all the options are available in AWS itself for Event routing and how to compare them with EventBridge. Here are the options for event routing:
  • CloudWatch Events
  • SNS
  • EventBridge
  • Kinesis
CloudWatch Events vs EventBridge

CloudWatch Events can support only AWS services as event sources. It uses only the default event bus. Default event bus accepts events from AWS services, PutEvents API calls, and other authorized accounts. You can manage permissions on the default event bus to authorize other accounts.

EventBridge provides an option to create custom event buses and SaaS event bus on top of the default bus. The custom event bus is used to handle custom events raised by using PutEvents APIs. SaaS event bus is used to channel through events triggered by SaaS platforms. 

For default bus, EventBridge leverages the CloudWatch Events API, so CloudWatch Events users can access their existing default bus, rules, and events in the new EventBridge console, as well as in the CloudWatch Events console.

SNS vs EventBridge

SNS is a well-known event sourcing service. It shines very well when the throughput is very high maybe millions of tps. EventBridge supports 400 requests per second only.

However, the number of targets supported by SNS is limited compared to EventBridge.
For example, if an event needs to trigger Step Functions, it cannot do it directly as it is not available as a Target. It needs to call Lambda function and that can trigger the Step Functions. On the other hand, EventBridge supports 17 targets as of now. But, each Rule in EventBridge can configure max 5 targets.

SNS scales practically infinitely, but filtering is limited to attributes, not event content. SNS doesn't give the guarantee on the ordering of the messages.

Kinesis vs EventBridge

Kinesis service can be used as an event routing as well as event storing. This is an ideal solution for processing real-time data at large. It can fan-out to multiple consumers however, there is a limitation on the number of consumers can connect to a single stream. Each individual consumer would be sort of responsible for the kind of filtering out any messages that they weren't potentially interested in.

Kinesis also provides ordering guarantees. However, it doesn't have an entirely usage-based pricing model. It doesn’t automatically scale to demand. 

On the other hand, EventBridge cannot buffer the events. It needs SQS or Kinesis integration for event storing. 

Use Cases -

Let's take a couple of use cases and see how they will be implemented using SNS and EventBridge.

1.  If I want to build a system where if an EC2 instance is down, it should reboot the EC2 instance and also trigger a Lambda function to store the incident to the DynamoDB table.

If I build it using SNS as an event routing service, it would need to use SQS as well as it cannot be subscribed by EC2 directly. Here is the design for this solution:


If we implement the same use case using EventBridge, the design will be like this:


We can see the design is much simpler. With a fewer number of services, we are able to implement it.

2.  Let's take another use case where an employee resigns from the Organization and his record is updated in the CRM tool. It needs to trigger different workflows for all the approvals as part of exit checklist.

If we implement this use case using SNS, the design will look something like this:


If we use EventBridge, the design will be much simpler. It doesn't need polling, CloudWatch Scheduler, and Lambda functions. The design will look somewhat like this:


Things to Remember

      Now, we understand what is EventBridge service and how it can be used to make our design simpler in AWS. Let's keep a few things in mind while using this service:
  • Pricing for EventBridge is same as CloudWatch Events. Its dollar per 1 Million events published to the event bus.
  • CloudFormation is still not supported for Custom/SaaS event bus. This feature is yet to be released. However, for default bus, it is supported.
  • EventBridge will ensure to have a successful delivery to Targets. If failure happens, it will retry for 24 hours only before marking it as failed. In the case of Lambda, what successful delivery means from the EventBridge perspective is that it was able to asynchronously invoke your function. So when it gets a success back from the Lambda service saying that, "hey, yeah, the invoke call you made with success.". So then, at that point, you're really kind of relying on the standard Lambda retry policy for the failure handling within that kind of async invoke flow.
  • EventBridge makes connection seamless for an AWS service from an AWS account to another AWS service in a different account. It has a target option as "event bus from another account".
  • EventBridge needs SQS to bring resiliency but kinesis has that feature built-in.

    • A word of warning on the event bus. It is very hard for consumers to use it without having some kind of event schema registry. Event Schema Registry makes it possible to search for an event type and to build version the schemas so consumers and publishers understand what they are working with.

    Summary

    In this article, we understood how EventBridge is helping to solve the SaaS platform integration with AWS services. Also, for existing AWS services, integration has become much simpler and smooth. However, from a security perspective, there is no much information documented for SaaS platform integration. For enterprise-level companies, it matters a lot as we are just giving AWS account id and region information to the vendor. I hope, documentation will mature eventually. 
    Rajesh Bhojwani December 01, 2019
    Read more ...
    AWS brought Serverless Application Model (SAM) to ease the building of the serverless application on AWS. At a high level, it is an extension of AWS CloudFormation. AWS SAM consists of two major components - SAM template specifications, SAM CLI.

    In this article, we are going to talk about 5 tips to get the most out of AWS SAM templates:

    1. Reuse Common Pattern using Nested Applications

    As serverless architectures grow, common patterns get reimplemented across teams, and projects. This hurts the development velocity and leading to wasted effort. To avoid that, AWS has come up with nested applications in AWS SAM and the AWS Serverless Application Repository (SAR) to make these patterns shareable publicly and privately.

    Nested applications are built off a concept in AWS CloudFormation called nested stacks. Serverless applications are deployed as stacks that contain one or more other serverless application stacks.

    Let's take an example. If we want to build an API made up of AWS Lambda and Amazon API Gateway, we can use AWS SAM to create Lambda functions, configure API Gateway, deploy and manage them both. Now, We want to secure this API. API Gateway has several methods for doing this. Let's say we want to implement basic HTTP Basic Auth. So, Instead of creating this functionality from scratch, we can search it in SAR.


    We can review the AWS SAM template, license, and permissions provided in SAR. If it meets our requirements, just copy the SAM Template of it and put it in our application SAM template under "Resources" tag.
    These applications will have a type - AWS::Serverless::Application

    Now, we can check the output of this application and refer that in the main API Authorizer like below:


    With this simple piece of code, we can reuse any existing code resided in SAR.

    2.  Reduce Line of Code Using Globals

    Serverless Architecture is all about breaking large application into smaller functions. So, if we end up having 10-20 Lambda functions for my application and we configure that in SAM template, we will notice so many Function definition under "Resources" tag.

    In AWS SAM template, Globals is a section to create properties common to all the Serverless Function and APIs.

    All the AWS::Serverless::Function and AWS::Serverless::Api resources will inherit the properties defined here. Here is a typical example:




    3. Enable a feature using SAM Parameter and Mappings

    Let's suppose we want to enable a feature in our application based on the flag value set in an environment variable. It can get complicated if we want to do it based on the deployment environment like testing/prod.
    For example, I have a feature "Download PDF" which I want to enable only in the test environment for now and don't want to publish to Prod until business approves it. So, the flow will be that an environment value (testing/prod) will be passed as a parameter. There should be a collection object like Map which should hold the status value (on/off) for each environment. Now, logic has to be put to retrieve the status dynamically and set in an environment variable so that the application can behave accordingly.
    Using SAM Parameters and Mapping tags, this can be done very easily. See below SAM template on how it is implemented.


    Here !FindInMap will search DocumentEnvironment parameter value (testing/staging/prod) in DownloadPDFFeature Map and retrieve "status" field value and set it with "Download_Feature1" variable.

    4. Safe Deployment using AutoPublishAlias and DeploymentPreference

    AWS Lambda has Versioning and Alias feature which helps to do the increment deployment of Functions. When an enhancement happens on a function, it can be published with a bumped-up version and an Alias can point to a version which we want to expose to the consumers. Below is the example:

    In SAM, we can bump-up this version by just using one property - AutoPublishAlias
     

    AWS SAM will do the following 3 tasks behind the scene:

    • Detect when new code is being deployed based on changes to the Lambda function's Amazon S3 URI.
    • Create and publish an updated version of that function with the latest code.
    • Create an alias with a name provided through ENVIRONMENT parameter and points to the updated version of the Lambda function.

    Apart from this, DeploymentPreference property will help to enable the canary and liner deployment strategy which ensures that if there is any problem with the newer version of the function, it can be rolled back. For example, in the above code, it is going to redirect only 10% of the traffic to the new version for 10 minutes and then keep increasing by 10% every 10 minutes. So, we can monitor the new version and rollback if any issues found.

    5. Enable Security using Policy Templates

    For any Lambda Function, the most important thing is to define what execution it can do and who can invoke it. That's where we define the security around it. SAM has a concept called Policy Templates. Using these templates, having 2 lines of code, corresponds to a complete IAM policy that will be keyed in.


    In the above example, we have used DynamoDBCrudPolicy template which corresponds to the below IAM policy.

    Using this feature we are able to reduce the complexity of the security configuration and standardize the security of Lambda Function.

    Summary

    AWS SAM has been introduced to reduce the complexity of building serverless applications and that is very evident by looking at above basic tips. There are several other features available in SAM but we will be parking them for the next article. That's all for now.

    Rajesh Bhojwani November 03, 2019
    Read more ...