Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check if boto3 S3.Client.upload_fileobj succeeded?

I want to save the result of a long running job on S3. The job is implemented in Python, so I'm using boto3. The user guide says to use S3.Client.upload_fileobj for this purpose which works fine, except I can't figure out how to check if the upload has succeeded. According to the documentation, the method doesn't return anything and doesn't raise an error. The Callback param seems to be intended for progress tracking instead of error checking. It is also unclear if the method call is synchronous or asynchronous.

If the upload failed for any reason, I would like to save the contents to the disk and log an error. So my question is: How can I check if a boto3 S3.Client.upload_fileobj call succeeded and do some error handling if it failed?

like image 518
Agost Biro Avatar asked May 16 '17 12:05

Agost Biro


People also ask

Do we need to close boto3 client?

There is little to gain by manually closing the boto connections because they are just HTTP connections and will close automatically after a few minutes of idle time. I wouldn't worry about trying to close them.

Does S3 Put_object overwrite?

put_object` does not overwrite the existing data in the bucket.

What is the difference between boto3 client and resource?

00:00 Boto3's primary function is to make AWS API calls for you. It extracts these APIs in two main ways: clients and resources. Clients give you low-level service access, while resources provide an object-oriented way of working with these services.

How do I know if my S3 bucket is empty boto3?

Boto3 resource doesn't provide any method directly to check if the key exists in the S3 bucket. Hence, you can load the S3 object using the load() method. If there is no exception thrown, then the key exists. If there is a client error thrown and the error code is 404 , then the key doesn't exist in the bucket.


2 Answers

I use a combination of head_object and wait_until_exists.

import boto3

from botocore.exceptions import ClientError, WaiterError

session = boto3.Session()
s3_client = session.client('s3')
s3_resource = session.resource('s3')


def upload_src(src, filename, bucketName):
    success = False

    try:
        bucket = s3_resource.Bucket(bucketName)
    except ClientError as e:
        bucket = None

    try:
        # In case filename already exists, get current etag to check if the 
        # contents change after upload
        head = s3_client.head_object(Bucket=bucketName, Key=filename)
    except ClientError:
        etag = ''
    else:
        etag = head['ETag'].strip('"')

    try:
        s3_obj = bucket.Object(filename)
    except ClientError, AttributeError:
        s3_obj = None

    try:
        s3_obj.upload_fileobj(src)
    except ClientError, AttributeError:
        pass
    else:
        try:
            s3_obj.wait_until_exists(IfNoneMatch=etag)
        except WaiterError as e:
            pass
        else:
            head = s3_client.head_object(Bucket=bucketName, Key=filename)
            success = head['ContentLength']

    return success
like image 132
reubano Avatar answered Oct 15 '22 03:10

reubano


There is a wait_until_exists() helper function that seems to be for this purpose in the boto3.resource object.

This is how we are using it:

s3_client.upload_fileobj(file, BUCKET_NAME, file_path)
s3_resource.Object(BUCKET_NAME, file_path).wait_until_exists()
like image 45
Mark Avatar answered Oct 15 '22 03:10

Mark