Let’s say you want to create a brand new Slack app. You are a cool developer, so you want to make it serverless. An obvious choice, nowadays, seems to be using AWS’s Lambda together with its API Gateway service.
So far, so good.
Your next choice is which programming language to use for your Lambda functions. Java remains one of the most popular languages, especially in the enterprise world, because it has a solid foundation, a strong community, well understood best practices, and open source projects. Ultimately, choosing to use Java for your serverless Slack app will allow you to take advantage of Java’s strong libraries & frameworks as well as its consistent performance. There are some real challenges to consider though, but I’ll show you how to address them.
In this article, I’ll compare how Java stacks up with Python or Node.js when it comes to building serverless Slack apps.
Advantages of using Java
Java is powerful and has the experience of decades
Java is old, but not out-dated! There are lots of good Java developers out there. Using a language you know well can save you a lot of time and trouble, which is usually a major advantage -- especially when you are looking at a big project.
With Java, you have all the powers provided by mature frameworks like Spring to develop your serverless Slack app. When it comes to well tested, proven open-source libraries and frameworks, Java has the clear advantage.
Tooling in Java is also very mature like the language itself. There are lots of cool IDE’s like Eclipse, and IntelliJ IDEA. AWS Toolkit for Eclipse supports serverless application development for Java by making creation and deployment of your functions a lot easier.
When it comes to performance, Java wins
For consecutive executions, Java is faster than Python and Node.js. For example, this github repository shows some representative benchmark tests and results comparing the languages in AWS Lambda. It is clear that Java wins in hot mode, even if it may not always be as fast when the function is cold. But don’t worry: I will talk about that -- and show you some workarounds -- in the next parts of this post!
In another blog post, while testing different languages in AWS Lambda, they have found out that Java has less variance than other languages in terms of execution duration. It means that Java is more consistent than other languages on AWS Lambda.
Disadvantages of using Java
Startup Latency can cause request timeouts
Slack expects responses to HTTP requests in three seconds (in order to optimize user experience) , using Java to create Slack apps may result in timeouts. This can happen as a result of the operation of Lambda functions and the nature of Java class loading, which can make serverless Java applications vulnerable to startup latency problem. I will explain the problem -- but please don’t stop reading! As I already said, I have some ideas for dealing with this, and I will share them later.
AWS Lambda functions execute in a container (sandbox) that isolates them from other functions. When the containers are created first time or their code or configuration updated, your functions experience a startup latency. This is also called “cold start”. You can learn more about this concept from Tim Wagner’s blog post where he explains the reason behind this latency and how they try to reduce the chances of us experiencing the problem by leveraging container reuse. Although the blog post talks about Node.js, the concept is the same for other languages.
Java functions take far longer to run during cold starts than Node.js or Python functions do, because Java’s class loading can contribute significant delays. This latency is mostly negligible in other languages. If your memory is low, class loading contributions to startup latency can cause cold starts to exceed three seconds.
Those three seconds can be a critical threshold for Slack applications: Remember: Slack expects responses to HTTP requests in three seconds.
This means that delay caused by cold start latency can be one of the most important disadvantages of using Java in your serverless Slack app. It is only a matter of time until one of your users gets an HTTP 500 error because your Lambda function’s cold start took more than three seconds…
As a note; when you run your functions inside a VPC, cold start delays can take substantially longer! For more information, you can check out this blog post with more information about Lambda and VPCs.
But don't get discouraged: there are some ways to deal with this problem - and I will tell you about them below!
Creating and maintaining a Serverless Slack App written in Java can take extra effort
Support for other languages can be better. Slack’s support for Node.js and Python includes official developer kits and open-source libraries. Slack also has open source client libraries for Java. As Slack is constantly enhancing its application and adding new features, open source project developers may not always be able to update the libraries as quickly for a language, like Java, with such large numbers of variables.
Java objects must be defined by variable names and types. For example:
As you see, even for such a simple object, you must create a channel object and specify each variable’s type. Although specifying the object types has its advantages, if you consider the speed with which Slack enhancements are introduced and the large numbers of Java variables needed, you can see that defining and maintaining the necessary Java objects for Slack can keep you hopping!
You still want to use Java? Good: let's make it work!
If you still want to go with a serverless Java app, let’s see how we can overcome some of those disadvantages...
Try to use community driven open-source libraries for your Slack app.
You can refer to this list of available Java libraries for Slack. It will save you lots of time to not to write all these functionalities by yourself.
Compensate for startup latency by increasing your function’s memory size (decrease startup times).
That will enhance both memory and CPU usage, resulting in faster startup times. At the same time, remember that increasing memory will also increase your Lambda function’s execution costs.
Keep your function active by having your application make periodic function calls.
That can reduce the risk of experiencing cold starts if your function is only used occasionally.
Reduce the risk and impact of excessive delays by implementing your flows asynchronously.
This can help if you spend a large portion of your precious three seconds on cold starts or if your function takes more than three seconds to execute, excluding cold starts. Basically, you should send messages to a queue and return success messages to Slack immediately. Then, you consume the queue and execute the real action. From that point, it is easy to update previously-sent success messages by using a response_url parameter (explained in "Responding to a command, Delayed responses and multiple responses").
Another way to update Slack messages asynchronously is to use the chat.update method in the Slack Web API. The first approach only allows you to respond to a user's command up to five times within 30 minutes of the command's invocation; the chat.update method does not have this limitation.
Good luck with your serverless Slack App (let us know how you do).
And don’t forget to follow the OpsGenie Engineering blog to learn more about serverless -- and much more!
If you still have time take a look at our blog post "Best Practices for Incident Management on Slack with OpsGenie" to learn more about how OpsGenie help you take your ChatOps experience next level!