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

FastAPI部署GCP Cloud Run上传媒体遇504超时错误求助

GCP Cloud Run部署FastAPI后端出现504 upstream request timeout问题

本地运行完全正常,但部署到GCP Cloud Run后,调用/create-pharmacy-user-form接口连续数日出现504 : upstream request timeout错误。相关代码如下:

接口代码

@router.post("/create-pharmacy-user-form", status_code=status.HTTP_201_CREATED)
async def create_form_user(
        db: db_dependency,  # Database dependency
        user_email: str = Form(...),
        user_password: str = Form(...),
        user_first_name: str = Form(...),
        user_last_name: str = Form(...),
        user_phone_number: str = Form(...),
        user_city: str = Form(...),
        user_country: str = Form(...),
        local_name: str = Form(...),
        user_newsletter_subscription: bool = Form(...),
        local_image: UploadFile = File(...),
        local_ice: UploadFile = File(...),
        local_patent: UploadFile = File(...)
    ):
    user_interface = UserInterface(db)
    
    try:
        # transform base 64 to file
        print("Endpoint called")
        user_data = {
            "user_email": user_email,
            "user_password": user_password,
            "user_first_name": user_first_name,
            "user_last_name": user_last_name,
            "user_phone_number": user_phone_number,
            "user_city": user_city,
            "user_country": user_country,
            "local_name": local_name,
            "local_image": local_image,
            "local_ice": local_ice,
            "local_patent": local_patent,
            "user_newsletter_subscription": user_newsletter_subscription,
        }
        db_user = user_interface.create_pharmacy_user(user_data)
        print("Uploading image")
        # Call the image upload function (ensure this is atomic or does not affect DB consistency)
        try :
            post_images(db_user["local_id"], user_data["local_image"], "pharmacy_images")
            print("Image uploaded")

            # Upload documents
            post_document(db_user["user_id"], user_data["local_ice"], "pharmacy_ices")
            post_document(db_user["user_id"], user_data["local_patent"], "pharmacy_patents")
            print("Documents uploaded")
        except Exception as e:
            print(e)

        #posting media
        return api_response(
            message="User created successfully",
            data=db_user,
            status_code=201
        )
    except Exception as e:
        return api_response(
            message="User creation failed: " + str(e),
            status_code=500
        )

文件上传函数代码

def post_images(image_id: uuid.UUID, image_file: UploadFile, path: str):
    bucket_name = settings.BUCKET_NAME
    service_account_json = settings.SERVICE_ACCOUNT_JSON

    try:
        # Open image directly from UploadFile's file object
        print("Opening image file")
        # Initialize GCS client
        client = storage.Client.from_service_account_json(service_account_json)
        bucket = client.bucket(bucket_name)

        # Generate a unique blob name
        blob_name = f"{path}/{image_id}.webp"
        blob = bucket.blob(blob_name)

        # Upload image to GCS
        blob.upload_from_file(image_file.file, content_type=image_file.content_type)
        print("Image uploaded successfully")
        print(blob.public_url)
        return {"image_id": str(image_id), "url": blob.public_url}

    except Exception as e:
        print("Error uploading image:", e)
        raise HTTPException(status_code=500, detail="Image upload failed.")


def post_document(document_id: uuid.UUID, document_file: UploadFile, path: str):
    bucket_name = settings.BUCKET_NAME
    service_account_json = settings.SERVICE_ACCOUNT_JSON

    try:
        # Read the file asynchronously
        print("Reading Document file")

        # Guess the mime type of the file
        mime_type = mimetypes.guess_type(document_file.filename)[0] or "application/octet-stream"
        extension = mimetypes.guess_extension(mime_type) or ".bin"

        # Create a file-like object in memory

        # Generate a unique file name with the correct extension
        blob_name = f"{path}/{document_id}{extension}"

        # Initialize GCS client
        client = storage.Client.from_service_account_json(service_account_json)
        bucket = client.bucket(bucket_name)
        blob = bucket.blob(blob_name)

        # Upload the file to GCS asynchronously
        blob.upload_from_file(document_file.file, content_type=mime_type) 
        print("Document uploaded")
        print(blob.public_url)

        return True

    except Exception as e:
        print("Error uploading document:", e)
        raise HTTPException(status_code=500, detail="Document upload failed.")

排查与解决建议

  • 调整Cloud Run超时配置:Cloud Run默认请求超时为5分钟,若文件上传耗时较长,需在Cloud Run服务设置中延长超时时间(最大可设为60分钟)。
  • 优化GCS客户端初始化:每次上传都重新初始化GCS客户端会增加开销,建议全局复用客户端实例,避免重复创建连接。
  • 异步化文件上传操作:当前接口在同步线程中执行文件上传,可改用异步GCS客户端,或把文件上传任务放入后台队列(如Cloud Tasks),先返回用户创建成功的响应,再异步处理上传,避免请求超时。
  • 检查文件上传大小限制:Cloud Run单请求最大 payload 限制为32MB,若上传文件总大小接近或超过该值,会导致请求处理超时,需拆分请求或改用分片上传。
  • 添加日志与监控:在文件上传的关键节点增加详细日志,结合Cloud Logging查看请求处理的耗时分布,定位具体是数据库操作还是文件上传环节超时;同时配置Cloud Monitoring的请求超时告警,便于实时排查。
  • 验证服务账号权限:确保Cloud Run服务账号拥有GCS存储桶的写入权限,权限不足可能导致上传停滞引发超时。
  • 优化文件上传方式:使用blob.upload_from_file时,可设置chunk_size参数(如chunk_size=1024*1024)分块上传,提升大文件上传的稳定性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 07:05:03