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

如何解决Python 3.5中Sanic框架多进程的OSError问题?

解决Sanic+multiprocessing后台运行终端关闭后的OSError问题

这个问题我之前在部署Python后台服务时也碰到过,核心原因很明确:当你关闭终端后,后台运行的Sanic主进程以及它用multiprocessing创建的子进程,都会失去与终端的关联——原来的标准输出(stdout)和标准错误(stderr)文件描述符已经变成无效状态,子进程尝试执行sys.stdout.flush()时就会触发OSError: [Errno 5] Input/output error。

下面给你几个实用的解决方案,按优先级排序:

1. 重定向子进程的输出流到文件或/dev/null

直接在子进程启动时,把stdout和stderr重定向到不会随终端关闭失效的位置,比如日志文件或者系统的空设备(/dev/null)。这样子进程就不会再尝试刷新已经无效的终端输出流了。

示例代码:

import os
import sys
from multiprocessing import Process
from sanic import Sanic, json

app = Sanic("background_upload_app")

def background_upload(file_data):
    # 重定向stdout和stderr到/dev/null(如果不需要日志可以用这个)
    # 或者替换成你的日志文件路径,比如'/var/log/sanic_upload.log'
    target_path = os.devnull
    with open(target_path, 'w') as f:
        os.dup2(f.fileno(), sys.stdout.fileno())
        os.dup2(f.fileno(), sys.stderr.fileno())
    
    # 执行你的文件上传逻辑
    try:
        # 模拟上传过程
        with open(f'/tmp/uploaded_{file_data.name}', 'wb') as out_file:
            out_file.write(file_data.body)
    except Exception as e:
        print(f"Upload failed: {e}")  # 现在会写到/dev/null或者指定日志文件

@app.route('/upload', methods=['POST'])
async def upload(request):
    file = request.files.get('file')
    if file:
        Process(target=background_upload, args=(file,)).start()
        return json({'status': 'accepted', 'message': 'Uploading in background'})
    return json({'status': 'error', 'message': 'No file provided'}, status=400)

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8000)

2. 使用logging模块统一管理日志

把所有打印输出替换成Python标准库的logging模块,将日志写入文件而非终端。这种方式更规范,也方便后续排查问题。

示例代码:

import logging
from logging.handlers import RotatingFileHandler
from multiprocessing import Process
from sanic import Sanic, json

app = Sanic("background_upload_app")

def setup_logging():
    # 配置日志处理器,写入文件并自动轮转
    logger = logging.getLogger()
    logger.setLevel(logging.INFO)
    
    # 避免重复添加处理器
    if not logger.handlers:
        handler = RotatingFileHandler(
            '/var/log/sanic_upload.log',
            maxBytes=10*1024*1024,  # 10MB
            backupCount=5
        )
        formatter = logging.Formatter(
            '%(asctime)s - %(processName)s - %(levelname)s - %(message)s'
        )
        handler.setFormatter(formatter)
        logger.addHandler(handler)

def background_upload(file_data):
    logger = logging.getLogger(__name__)
    logger.info(f"Starting background upload for file: {file_data.name}")
    try:
        with open(f'/tmp/uploaded_{file_data.name}', 'wb') as out_file:
            out_file.write(file_data.body)
        logger.info(f"Successfully uploaded file: {file_data.name}")
    except Exception as e:
        logger.error(f"Upload failed for {file_data.name}: {str(e)}")

@app.route('/upload', methods=['POST'])
async def upload(request):
    file = request.files.get('file')
    if file:
        Process(target=background_upload, args=(file,)).start()
        return json({'status': 'accepted', 'message': 'Uploading in background'})
    return json({'status': 'error', 'message': 'No file provided'}, status=400)

if __name__ == '__main__':
    setup_logging()
    app.run(host='0.0.0.0', port=8000)

3. 用进程管理工具启动应用(推荐生产环境)

在生产环境中,不要直接用&后台运行,而是用nohup或者systemd这类工具来管理进程,它们会自动处理输出流的重定向,避免终端关闭导致的问题。

  • 用nohup启动:

    nohup python3 your_app.py > /var/log/sanic_app.log 2>&1 &
    

    这条命令会把应用的所有输出(stdout和stderr)写入指定的日志文件,即使终端关闭,进程也会继续运行。

  • 用systemd做成服务:
    创建一个/etc/systemd/system/sanic-upload.service文件:

    [Unit]
    Description=Sanic Background Upload Service
    After=network.target
    
    [Service]
    User=your_username
    WorkingDirectory=/path/to/your/app
    ExecStart=/usr/bin/python3 your_app.py
    Restart=always
    StandardOutput=append:/var/log/sanic_upload.log
    StandardError=append:/var/log/sanic_upload.log
    
    [Install]
    WantedBy=multi-user.target
    

    然后启动并设置开机自启:

    sudo systemctl daemon-reload
    sudo systemctl start sanic-upload
    sudo systemctl enable sanic-upload
    

这样配置后,应用会由systemd管理,即使服务器重启也会自动启动,日志也会稳定写入文件,彻底避免终端相关的IO错误。

内容的提问来源于stack exchange,提问作者sunil barve

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 10:08:25