You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

脚本结束/中断后上传文件至S3报错:解释器关闭后无法调度新Futures

解决脚本中断时S3上传的RuntimeError问题

问题背景

需求:确保脚本无论正常结束还是被中断(比如按下CTRL+C),都能将指定文件上传至S3。

已实现的代码:

import atexit
import signal
atexit.register(exit_handler)
signal.signal(signal.SIGINT, exit_handler)
signal.signal(signal.SIGTERM, exit_handler)
def exit_handler():
    s3_client = boto3.client('s3')
    s3_client.upload_file(file,bucket, file)

触发CTRL+C中断时,出现如下报错:

File "/python3.10/site-packages/s3transfer/futures.py", line 474, in submit
    future = ExecutorFuture(self._executor.submit(task))
  File "/python3.10/concurrent/futures/thread.py", line 169, in submit
    raise RuntimeError('cannot schedule new futures after '
RuntimeError: cannot schedule new futures after interpreter shutdown

问题原因

这个错误的核心是:当通过CTRL+C触发SIGINT信号时,信号处理函数和atexit注册的回调会在Python解释器开始关闭流程后执行。而boto3的upload_file默认用多线程(依赖concurrent.futures)处理上传任务,此时解释器已进入shutdown状态,无法再创建新线程/ futures,因此抛出RuntimeError。

解决方案

方案1:提前初始化S3客户端并禁用多线程

把S3客户端的初始化放在脚本启动阶段,而非退出回调中,同时配置客户端禁用多线程,避免在解释器关闭时创建新线程:

import atexit
import signal
import boto3
from botocore.config import Config

# 提前初始化S3客户端,设置单线程连接池
s3_config = Config(max_pool_connections=1)
s3_client = boto3.client('s3', config=s3_config)

# 替换为你的实际文件路径和桶名
local_file_path = "your_file.txt"
s3_bucket_name = "your-bucket-name"
s3_object_key = "your_file.txt"

def exit_handler(signum=None, frame=None):
    try:
        s3_client.upload_file(local_file_path, s3_bucket_name, s3_object_key)
        print("文件已成功上传至S3")
    except Exception as e:
        print(f"上传失败: {str(e)}")
    # 信号触发的中断,处理完成后主动退出
    if signum is not None:
        exit(0)

# 注册退出回调和信号处理
atexit.register(exit_handler)
signal.signal(signal.SIGINT, exit_handler)
signal.signal(signal.SIGTERM, exit_handler)

# 这里放你的主程序逻辑
# ...

方案2:使用单线程上传方式

如果不想修改客户端配置,也可以改用upload_fileobj方法,手动以单线程方式读取文件并上传:

def exit_handler(signum=None, frame=None):
    try:
        with open(local_file_path, 'rb') as f:
            s3_client.upload_fileobj(f, s3_bucket_name, s3_object_key)
        print("文件已成功上传至S3")
    except Exception as e:
        print(f"上传失败: {str(e)}")
    if signum is not None:
        exit(0)

额外注意点

  • 信号处理函数需要接收signum和frame两个参数(信号触发时会自动传入),之前的无参写法可能引发潜在错误
  • 建议在上传逻辑中增加异常捕获,避免上传失败时无提示信息

内容的提问来源于stack exchange,提问作者00__00__00

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 19:05:25