Distributed locking with AWS ElastiCache

It’s been a long time since we published an article about how to integrate AWS SWF in your microservice in order to have a mechanism for distributed locking. Distributed locking is a feature necessary in certain situation when one and only one entity from a mass has to perform a given task like generate a report, aggregate some stats, check for an update and so on.

While SWF is a good fit for this use case, it has at least one big drawback: it comes with many dependencies, plus support for aspect oriented programming. Another option from AWS about which we have spoken is Step Functions.

Today we are going to present another alternative for this scenario: how to use Redis from AWS ElastiCache to get a lock. There are several libraries for this use case, but we decided to implement this using Reddison because we noticed it has an active development.

The entire implementation is available here. Clone the repository, add in the configuration files the Redis endpoint and then start the service. If you don’t know how to connect to a Redis cluster hosted in AWS, open this post.

Once you started the service, try to make a call that simulates a report generation for a given client. Something like:

curl -X POST 'http://localhost:8080/report?client=cirrus'

And in the service logs you’ll see:

2018-12-31 12:52:21.735  INFO 24648 --- [nio-8080-exec-1] c.c.d.c.CirrusCloudDemoController        : /report request.
2018-12-31 12:52:21.822  INFO 24648 --- [nio-8080-exec-1] c.cirrustech.demo.service.ReportService  : Attempting to get lock for client cirrus. Result true
2018-12-31 12:52:21.822  INFO 24648 --- [nio-8080-exec-1] c.cirrustech.demo.service.ReportService  : Starting to generate report.

Basically, these lines tell us that this host acquired the lock for generating report for this client. In the implementation you can see that lock is kept for 30 seconds. If in this interval you are going to make another call for the same client, the response will be:

curl  -X POST 'http://localhost:8080/report?client=cirrus'
Report for client cirrus already started.

And in the logs we’ll find:

2018-12-31 13:04:50.624 INFO 24648 --- [nio-8080-exec-4] c.c.d.c.CirrusCloudDemoController : /report request.
2018-12-31 13:04:50.790 INFO 24648 --- [nio-8080-exec-6] c.cirrustech.demo.service.ReportService  : Attempting to get lock for client cirrus. Result false


Which means the lock is already taken by someone else. If you want to go further with this test, you can start the microservice in another terminal, but you have to start it on another port using server.port parameter. Something like: -Dserver.port=8081 argument. If you call the /report API for the same client, even you hit the other service endpoint, your call is going to be rejected.

In the end, we want to say that this example is provided just to demo that Redis can be used for this purpose. In fact, Redis is a great tool and if you use it correctly, it can be an excellent choice for many use cases.

Add you thoughts about this topic or if you use Redis in a different context and share this to anyone could be interested in!