如何在Python中找到S3多部分上传失败的地方



我正在实现一个cron作业,该作业将向S3 Bucket上传一个大的每日备份文件。它大多数时候都有效,但每隔一段时间,我就会检查bucket,文件大小明显小于实际大小。

它应该大约是50GB,但上次出现时,它显示为34GB。我的主要问题是我不确定该尝试/捕捉什么错误。

我仍然在学习Python,对我来说太枯燥了。

from progress import ProgressPercentage  # class file progress.py
from slack import *  # function file for Slack notifications
import random
import glob
import os
import boto3
import botocore
from boto3.s3.transfer import TransferConfig
bucket = "my-s3-backup"
s3 = boto3.resource('s3')
# Grabbing the last file, and removing the full path from the string
pattern = "/path/to/backup/file/xb_*"
files = list(filter(os.path.isfile, glob.glob(pattern)))
files.sort(key=lambda x: os.path.getmtime(x))
file_to_upload = files[-1]
file_name = file_to_upload.replace('/path/to/backup/file/', '')
key_path = 'physical_db_backups/' + file_name
# Multipart upload function
def multi_part_upload():
config = TransferConfig(multipart_threshold=1024 * 25,
max_concurrency=10,
multipart_chunksize=1024 * 25,
use_threads=True)
try:
s3.meta.client.upload_file(file_to_upload, bucket, key_path, Config=config,
Callback=ProgressPercentage(file_to_upload))
# Custom Slack notification to inform completion
sendslacksuccess("Physical Backup to S3 Complete:n" + file_name)
except botocore.exceptions.ClientError as error:

# Custom Slack notification to inform of failure
sendslackerror("Physical Backup to S3 Failed:n" + file_name + "nError: " + error)

if __name__ == '__main__':
multi_part_upload()

如果脚本不是";失败;但它并没有上传完整的文件大小,我想在这里捕捉什么异常?我应该在某个地方记录输出吗?

我正在查看Botocore异常文档。我只是不确定用这个try/catch做什么。

供参考,这里是文件大小的差异:

aws s3 ls --summarize --human-readable --recursive s3://my-s3-backup/physical_db_backups/

2022-05-07 14:31:28   50.7 GiB physical_db_backups/xb_202205070101.xb.zst
2022-05-08 12:48:07   50.8 GiB physical_db_backups/xb_202205080101.xb.zst
2022-05-09 01:30:04   34.2 GiB physical_db_backups/xb_202205090101.xb.zst <--- WRONG

好吧,因为我是个白痴,没有意识到文件还没有完成,所以我做了一些更改。

  1. 我编辑了cron以便稍后启动。

  2. 我已经创建了逻辑来确定备份脚本是否正在运行。

  3. 我可能会进行额外的检查以确保文件存在,但目前这是一个经过测试的工作POC。

    from progress import ProgressPercentage  # class file progress.py
    from slack import *  # function file for Slack notifications
    import random
    from time import sleep
    import psutil
    import glob
    import os
    import boto3
    import botocore
    from boto3.s3.transfer import TransferConfig
    import logging
    bucket = "fsn-s3-backup"
    s3 = boto3.resource('s3')
    pattern = "/path/to/backup/file/xb_*"
    files = list(filter(os.path.isfile, glob.glob(pattern)))
    files.sort(key=lambda x: os.path.getmtime(x))
    file_to_upload = files[-1]
    file_name = file_to_upload.replace('/path/to/backup/file/', '')
    key_path = 'physical_db_backups/' + file_name
    logging.basicConfig(filename='/var/log/s3-backup.log', format='%(asctime)s - %(levelname)s - %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p', filemode='a')
    logger = logging.getLogger()
    logger.setLevel(logging.INFO)
    
    def multi_part_upload():
    config = TransferConfig(multipart_threshold=1024 * 25,
    max_concurrency=10,
    multipart_chunksize=1024 * 25,
    use_threads=True)
    try:
    s3.meta.client.upload_file(file_to_upload, bucket, key_path, Config=config,
    Callback=ProgressPercentage(file_to_upload),
    ExtraArgs={'ContentType': 'application/zstd'})
    logger.info("Physical Backup to S3 Complete")
    sendslacksuccess("Physical Backup to S3 Complete:n" + file_name)
    except botocore.exceptions.ClientError as error:
    logger.error("Physical Backup to S3 Failed: " + error)
    sendslackerror("Physical Backup to S3 Failed:n" + file_name + "nError: " + error)
    
    def checkIfProcessRunning(processName):
    for proc in psutil.process_iter():
    cmdline = proc.cmdline()
    if processName in cmdline:
    return True
    return False
    
    if __name__ == '__main__':
    backuprunning = True
    while backuprunning:
    logger.info("Checking if backup shell script is running")
    if checkIfProcessRunning('/path/to/physical_backup.sh'):
    logger.info("Backup shell script still running. Sleeping for 60s")
    sleep(60)
    else:
    backuprunning = False
    logger.info("Beginning multipart upload")
    multi_part_upload()