Skip to content

Latest commit

 

History

History
264 lines (196 loc) · 6.7 KB

File metadata and controls

264 lines (196 loc) · 6.7 KB

🐛 檔案下載問題診斷與修復

❌ 問題描述

錯誤路徑: /api/file/aace66ae-f814-4fa0-8a7b-bc0f1f8c10dc

症狀: 點擊「📥 下載檔案」按鈕後,無法下載檔案


🔍 可能原因

1. 任務狀態問題

  • 下載任務未完成 (status != 'completed')
  • 任務 ID 不存在

2. 檔案路徑問題

  • 檔案路徑為 None 或空字串
  • 檔案路徑是相對路徑,在容器中無法找到
  • 檔案在下載後被刪除或移動

3. Railway 容器問題

  • 檔案系統是臨時的 (ephemeral)
  • 權限問題
  • 多個 worker 之間無法共享記憶體狀態

✅ 已實施的修復

修復 1: 詳細日誌輸出

位置: app_pytubefix.py - download_file() 函數

@app.route('/api/file/<task_id>')
def download_file(task_id):
    print(f'📥 下載請求: task_id={task_id}')
    
    if task_id not in download_tasks:
        print(f'❌ 任務不存在: {task_id}')
        print(f'   現有任務: {list(download_tasks.keys())}')
        return jsonify({'error': '任務不存在'}), 404
    
    task = download_tasks[task_id]
    print(f'📋 任務狀態: {task["status"]}')
    
    if task['status'] != 'completed':
        print(f'⚠️ 下載未完成: status={task["status"]}')
        return jsonify({'error': f'下載未完成 (狀態: {task["status"]})'}, 400)
    
    file_path = task.get('file_path')
    print(f'📁 檔案路徑: {file_path}')
    
    if not os.path.exists(file_path):
        print(f'❌ 檔案不存在: {file_path}')
        print(f'   downloads 目錄內容: {os.listdir(DOWNLOAD_FOLDER)}')
        return jsonify({'error': f'檔案不存在'}), 404
    
    print(f'✅ 開始傳送檔案: {task["filename"]}')

好處: 可以在 Railway 日誌中看到詳細的錯誤訊息

修復 2: 使用絕對路徑

位置: app_pytubefix.py - 初始化和下載完成

# 初始化時
DOWNLOAD_FOLDER = os.path.abspath(os.path.join(os.path.dirname(__file__), 'downloads'))
print(f'📁 下載目錄: {DOWNLOAD_FOLDER}')

# 下載完成時
download_tasks[task_id]['file_path'] = os.path.abspath(file_path)  # 絕對路徑
print(f'   路徑: {download_tasks[task_id]["file_path"]}')
print(f'   存在: {os.path.exists(download_tasks[task_id]["file_path"])}')

好處: 確保路徑在容器中正確解析

修復 3: 錯誤處理增強

try:
    return send_file(
        file_path,
        as_attachment=True,
        download_name=task['filename']
    )
except Exception as e:
    print(f'❌ 傳送檔案失敗: {e}')
    traceback.print_exc()
    return jsonify({'error': f'傳送檔案失敗: {str(e)}'}), 500

好處: 捕獲 send_file 的錯誤


🧪 部署後診斷步驟

1. 等待 Railway 部署完成

前往 Railway Dashboard → Deployments → 等待狀態變為 "Active"

2. 測試下載並查看日誌

操作步驟:

  1. 貼上 YouTube 網址
  2. 選擇音訊或影片
  3. 開始下載
  4. 等待 100%
  5. 點擊「📥 下載檔案」

同時查看 Railway 日誌 (View Logs):

預期正常日誌:

📁 下載目錄: /app/downloads
✅ 下載目錄已存在: /app/downloads

# 下載時
✅ 下載完成: test_video.mp3
   檔案大小: 5.82 MB
   檔案格式: .mp3
✅ 任務完成!
   檔案: test_video.mp3
   路徑: /app/downloads/test_video.mp3
   存在: True

# 下載檔案時
📥 下載請求: task_id=aace66ae-f814-4fa0-8a7b-bc0f1f8c10dc
📋 任務狀態: completed
📁 檔案路徑: /app/downloads/test_video.mp3
✅ 開始傳送檔案: test_video.mp3

如果出現錯誤,日誌會顯示:

錯誤 1: 任務不存在

📥 下載請求: task_id=aace66ae-f814-4fa0-8a7b-bc0f1f8c10dc
❌ 任務不存在: aace66ae-f814-4fa0-8a7b-bc0f1f8c10dc
   現有任務: []

原因: 多個 worker 導致記憶體不共享 解決: 設定 --workers 1 或使用資料庫/Redis 儲存任務狀態

錯誤 2: 下載未完成

📥 下載請求: task_id=aace66ae-f814-4fa0-8a7b-bc0f1f8c10dc
📋 任務狀態: downloading
⚠️ 下載未完成: status=downloading

原因: 下載還在進行中 解決: 等待下載完成

錯誤 3: 檔案不存在

📥 下載請求: task_id=aace66ae-f814-4fa0-8a7b-bc0f1f8c10dc
📋 任務狀態: completed
📁 檔案路徑: /app/downloads/test_video.mp3
❌ 檔案不存在: /app/downloads/test_video.mp3
   downloads 目錄內容: []

原因: 檔案在下載後消失 (容器重啟或檔案系統問題) 解決: 檢查容器是否重啟,或使用外部儲存 (S3, Cloudinary)


🔧 進一步修復方案

問題: 多個 Worker 導致記憶體不共享

症狀: 任務在一個 worker 創建,但在另一個 worker 查詢時找不到

當前設定: --workers 2 (Dockerfile 和 start.sh)

解決方案 1: 使用單一 Worker

修改 Dockerfile:

CMD gunicorn app_pytubefix:app --bind 0.0.0.0:$PORT --workers 1 --timeout 300

修改 start.sh:

exec gunicorn app_pytubefix:app --bind 0.0.0.0:$PORT --workers 1 --timeout 300

優點: 簡單,記憶體狀態一致 缺點: 無法同時處理多個請求

解決方案 2: 使用資料庫儲存任務狀態 (未來改進)

使用 SQLite 或 Railway PostgreSQL:

# 替代 download_tasks = {} 記憶體字典
# 使用資料庫表儲存任務狀態

📊 檢查清單

部署後檢查

  • Railway 部署狀態為 "Active"
  • 日誌中有 📁 下載目錄: /app/downloads
  • 日誌中有 ✅ 下載目錄已存在
  • 測試下載音訊
  • 日誌中有 ✅ 任務完成!
  • 日誌中顯示 存在: True
  • 點擊下載檔案
  • 日誌中有 📥 下載請求
  • 日誌中有 ✅ 開始傳送檔案
  • 檔案成功下載到瀏覽器

如果失敗

  • 截圖 Railway 日誌 (包含錯誤訊息)
  • 記錄 task_id
  • 檢查是否有多個 worker
  • 嘗試設定 --workers 1

🎯 預期結果

成功下載流程:

  1. 開始下載 → 創建任務,返回 task_id
  2. 下載中 → 顯示進度 0% → 100%
  3. 轉換 (音訊) → 顯示 "轉換為 MP3..."
  4. 完成 → 狀態變為 "completed"
  5. 點擊下載 → 瀏覽器開始下載 .mp3 或 .mp4 檔案

日誌確認:

✅ 任務完成!
   檔案: test_video.mp3
   路徑: /app/downloads/test_video.mp3
   存在: True
📥 下載請求: task_id=xxx
✅ 開始傳送檔案: test_video.mp3

📚 修改記錄

Commit: 0ce5454

修改內容:

  • ✅ 添加詳細下載日誌
  • ✅ 使用絕對路徑儲存檔案
  • ✅ 增強錯誤處理
  • ✅ 添加檔案存在性檢查
  • ✅ 添加 downloads 目錄內容輸出

建立時間: 2025-10-09
狀態: ✅ 修復已推送
下一步: 等待部署,查看 Railway 日誌診斷問題