AWS Lambda: Asynchronous Invocation Observations
September 19, 2018
AWS Lambda is great solution for a lot of problems but one might hit certain issues when pushing it to its limits. Let’s look at some interesting observations about it which can help us to work better with it.
A user can invoke a Lambda function either synchronously or asynchronously and the limits applied to the function depend on how a function is invoked, among other reasons. Some interesting aspects for asynchronous invocations are:
Internal invocation queue
Lambda internally uses an invocation queue (one per function) to manage the asynchronous invocations. Once invoked, Lambda queues the event and then executes it at a concurrency level that is compatible with the account, region and user limits.
For a scenario where you have a bug in the invoked function and you want to stop it, these features can be problematic. Some workarounds are:
- Pre-step: Throttle the function.
One can throttle the function concurrency to 0
, if necessary, to
Immediately stop the execution of the queued events.
- Contact AWS support to clear the invocation queue
This is the cleanest way to purge the invocation queue though AWS might roll out a way for customers to view and edit the invocation queue themselves. The downside is of course the turnaround time.
- Delete the function!
By deleting the queued function, a user can clear the invocation queue regardless of how many invocations are in the queue. It’s a quick and dirty way to get out of a messy situation but remember that all invocations that happen when the function is in deleted state are lost. Ensure you have a way to re-trigger your asynchronous functions.
- Just wait!
AWS deletes all queued events in the invocation queue after 4 days (unofficial information, no guarantees about it and it might vary depending upon your account specifics).
“Pause, Update and Continue”
If you find a bug in an asynchronously invoked function and you only care about the new invocations, an approach that could help is:
- Throttle the concurrency of the asynchronous function to
0
- Update the function code with a bug fix
- Increase the concurrency limit to
1
or more and continue from where you paused
Retries
Lambda can retry a function execution for a number of reasons. Being aware of this is important for asynchronous invocations since the only feedback that you get is from CloudWatch (no synchronous responses!). Ensure that the side-effects of your functions are idempotent for best results.
Multi-level fan-out
Asynchronous invocations are a great way to quickly scale up the concurrency
level of the invocations and also, get around the execution time limitation of
300
seconds per function. An approach would look like this.
- Invoke
function_1
function_1
invokesfunction_2
x
times- Each
function_2
invocation in turn invokesfunction_3
y
times
Such a setup lets you invoke function_3
x * y
times very quickly.
e.g., let’s say you need to invoke function_3
10000 times and time needed to
invoke this function is 10ms.
Sequential invocation
Total time = 10000 * 10ms
= 100 seconds
Fan-out invocation
Level 1: 1 * 10ms
(function_1
invoked)
Level 2: 100 * 10ms
(function_2
invoked 100 times by function_1
)
Level 3: 100 * 10ms
(function_3
invoked 100 times by every invocation of function_2
)
Total time = 10ms + 1000ms + 1000ms
= 2.1 seconds
The result of the fan-out method of invocation is two orders of magnitude faster and it works because Lambda functions support a high level of concurrency.
Certain caveats with this are:
- Ensure your concurrency limits are high enough for this or request for an increase in concurrency limits
function_3
execution happens with very high concurrency. This limits that options that this function can perform to other highly concurrent applications. e.g., you might not be able to update a RDBMS database. Additionally, you may get throttled by applications that usually support concurrent access, but cannot support the sudden spike of traffic.
Speed of invocation
Time required to invoke a Lambda function asynchronously is in the neighborhood of 10ms to 25ms (tested with Golang. It might change with the programming language and might improve in the future).
Summary
Asynchronous invocation can be a powerful tool in a serverless programmer’s toolbelt. Be aware of the pitfalls and the performance considerations for best results.