Lambda is great for Microservices. The API Gateway pattern is a major exception to my rule that “if you have one Lambda calling another you’re probably doing it wrong”. It makes complete sense to build an API gateway as a single microservice handling common tasks like authentication then invoke Lambdas from another microservice to perform actions.
The problem is that a lot of people (especially starting out) equate a Lambda function to a regular function inside their code and start splitting up validation, database access, sending emails, etc as separate Lambda’s all invoked from a main Lambda.
Trying thinking of the code in your Lambda as stuff that needs to happen before you respond to the user and stuff that can happen after. Anything that needs to happen before should be part of a single Lambda. Anything that can happen after should generally be connected via SNS which gives your lose coupling, retries, etc.
A customer places an order (order service). You need to tell the warehouse (warehouse service) to pick the item and package it for shipping. If you’re invoking Lambda’s directly then either:
- The order service can’t create an order unless it can communicate with the warehouse service, or
- You now need to build a retry mechanism into the order service.
But there are more problems:
- Your order service needs to understand which function to call and how to call it in order to initiate picking. What happens if this changes in the warehouse service?
- What happens if the warehouse services needs to call other services? Could the order services now get delayed for seconds or minutes while accepting an order?
- When you need to add/remove other functionality (perhaps sending a receipt from a receipt service) then you need to keep modifying the order service.
The alternative is to publish a “new order” message via SNS. Services that are interested in knowing about new orders can listen for this. If the warehouse service is temporarily down then orders don’t stop. When the receipt service is added the order service isn’t modified. This is loose coupling.
This doesn’t mean that one Lambda never needs to invoke another. But you should ask yourself
- Does this functionality really belong in another Lambda?
- Can I use another mechanism to invoke it?