Boto3 updates & Lambda runtimes
Context
While working on a search platform implementation, I found out that the AWS service (Amazon Kendra in this case) had a few new apis for us to play around with – one of them being get_snapshots.
Usecase:
- Get the top searched query items into a list for some other team to consume.
Problem Statement
When the updated api is used, the lambda console doesn’t seem to agree on its availability.
Lambda code :
import boto3
client=boto3.client('kendra')
def handler(event, context):
response = client.get_snapshots( IndexId="****", Interval="THIS_WEEK", MetricType="QUERIES_BY_ZERO_RESULT_RATE", MaxResults=5 ) print(response)
Response:
{
"errorMessage" : " 'kendra' has no attribute 'get_snapshots' ",
"errorType": "AttributeError", ...}
But, the api is available in the boto3 and Kendra documentation. What did I do wrong here ? Before we get there, lets dig into one component here : boto3
What is Boto3
Boto3 is primarily the AWS SDK for Python to create, configure, and manage AWS service. The SDK provides an object-oriented API as well as low-level access to AWS services. If you are working on an application or infrastructure which involves some serverless stack, you would deal with AWS Lambda and if python is your choice of language, boto3 is what you would deal with. I even think the entire aws cli ecosystem is underpinned by this boto3 implementation.
The usage is as simple as
import boto3
client=boto3.client('<nameOfService>')
RootCause
If I had paid attention to the api version, I would have realized that the boto3 api upgraded to 1.20.53 and the newest api updates I was referring to were present only in the latest version.
So , who was the culprit ? Let’s do one more thing before we take that api response for granted.
>>> import boto3
>>> client=boto3.client('kendra')
>>> print(dir(client))
['_PY_TO_OP_NAME', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattr__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_cache', '_client_config', '_convert_to_request_dict', '_emit_api_params', '_endpoint', '_exceptions', '_exceptions_factory', '_get_waiter_config', '_load_exceptions', '_loader', '_make_api_call', '_make_request', '_register_handlers', '_request_signer', '_response_parser', '_serializer', '_service_model', 'batch_delete_document', 'batch_put_document', 'can_paginate', 'create_data_source', 'create_faq', 'create_index', 'create_thesaurus', 'delete_data_source', 'delete_faq', 'delete_index', 'delete_thesaurus', 'describe_data_source', 'describe_faq', 'describe_index', 'describe_thesaurus', 'exceptions', 'generate_presigned_url', 'get_paginator', 'get_waiter', 'list_data_source_sync_jobs', 'list_data_sources', 'list_faqs', 'list_indices', 'list_tags_for_resource', 'list_thesauri', 'meta', 'query', 'start_data_source_sync_job', 'stop_data_source_sync_job', 'submit_feedback', 'tag_resource', 'untag_resource', 'update_data_source', 'update_index', 'update_thesaurus', 'waiter_names']
Clearly get_snapshots attribute is not present in the Kendra client and the error response was not a lie. Why did this happen ?
I started looking at lambda-runtime documentation on the different runtimes and supported SDK versions.
So what is running on the lambda container right now ?
import boto3
client=boto3.client('kendra')
def handler(event, context):
print(f"Boto3 version: {boto3.__version__}")
Output:
Boto3 version: 1.18.55
This matches the reference documentation for lambda runtimes. So the lambda runtime is currently behind the boto3 latest version by a minimum of 2 major versions.
Conclusion:
- If you are dependent on latest versions of boto3 apis, review the lambda filesystem to check the module version which is imported automatically before using them.
- If you require that boto3 version to be changed, you can have that brought in as a layer for your lambda which means your deployment needs to consider that.
- A very rudimentary way is described here as well.
I hope the AWS Lambda teams looks to allow an easier way to manage this through the console or some config parameter.