Developer Guide

Hướng Dẫn Triển Khai Hệ Thống Ghi Lại Logs

Tài liệu chi tiết kiến trúc, cấu hình ghi log PM2, chống treo process workerd và xoay vòng log tự động

Hướng Dẫn Triển Khai Hệ Thống Ghi Lại Logs (Logging System Guide)

Tài liệu kỹ thuật chi tiết dành cho DevOps / Developer để triển khai, vận hành và quản lý hệ thống ghi log tập trung cho dự án OpenStory chạy trên môi trường Linux Server với PM2 và Cloudflare Wrangler / workerd.


1. Tổng Quan & Kiến Trúc Vận Hành

1.1. Kiến Trúc Tiến Trình Của OpenStory

Dự án OpenStory khi chạy môi trường local/server thông qua PM2 sử dụng lệnh:

wrangler dev --ip 0.0.0.0 --port 3033 --show-interactive-dev-session=false

Mô hình phân tầng tiến trình:

+-------------------------------------------------------+
| PM2 Process Manager (Daemon)                          |
+-------------------------------------------------------+
                           |
                           v (Spawns & Monitors)
+-------------------------------------------------------+
| Wrangler (Node.js) - Script Cha (Parent Process)      |
+-------------------------------------------------------+
                           |
                           v (Spawns runtime binary)
+-------------------------------------------------------+
| workerd (C++ Binary) - Tiến trình con (Child Process)  |
| -> Lắng nghe cổng mạng TCP 0.0.0.0:3033               |
| -> Chạy D1 SQLite, R2 Storage, Worker Backend Runtime |
+-------------------------------------------------------+

1.2. Sự Cố Phổ Biến & Nguyên Nhân Gốc Rễ

Khi hệ thống chạy liên tục sau nhiều ngày:

  1. Tràn bộ nhớ / Crash ngầm: Wrangler hoặc workerd chạm ngưỡng RAM (max_memory_restart) hoặc crash đột ngột.
  2. Tiến trình con bị mồ côi (Orphan workerd): Khi PM2 dừng hoặc restart tiến trình cha wrangler, mặc định tín hiệu SIGINT/SIGTERM không truyền xuống hết cây tiến trình con. Hậu quả là workerd vẫn sống độc lập (PPID = 1), giữ cổng 3033 ở trạng thái LISTEN và các socket bị CLOSE_WAIT.
  3. Lỗi đụng cổng (Address already in use) & 502 Bad Gateway: Instance mới khởi động cố gắng bind(0.0.0.0:3033) nhưng bị từ chối, dẫn đến crash loop liên tục và Nginx/Proxy trả về mã lỗi 502.

2. Cấu Hình PM2 Chuẩn Hóa (ecosystem.config.cjs)

File cấu hình ecosystem.config.cjs được tối ưu hóa toàn diện với các tham số:

const path = require('path');

module.exports = {
  apps: [
    {
      name: 'openstory',
      script: 'node_modules/wrangler/bin/wrangler.js',
      args: 'dev --ip 0.0.0.0 --port 3033 --show-interactive-dev-session=false',
      cwd: __dirname,
      interpreter: 'node',
      autorestart: true,
      watch: false,
      max_memory_restart: '2500M',

      // --- Cấu hình triệt tiêu tiến trình con & chống đụng port ---
      kill_timeout: 5000,    // Đợi 5s cho tiến trình giải phóng socket trước khi force kill
      treekill: true,        // Diệt toàn bộ cây tiến trình con (bao gồm binary workerd)
      restart_delay: 3000,   // Chờ 3s trước khi spawn lại để hệ điều hành nhả cổng hoàn toàn

      env: {
        CI: 'true',
        NODE_ENV: 'production',
        CLOUDFLARE_INCLUDE_PROCESS_ENV: 'true',
        VIDEO_EXPORT_DEV_URL: 'http://localhost:8088',
      },

      // --- Cấu hình ghi nhận logs tập trung ---
      log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
      error_file: path.join(__dirname, 'logs/openstory-error.log'),
      out_file: path.join(__dirname, 'logs/openstory-out.log'),
      merge_logs: true,
    },
    {
      name: 'openstory-export',
      script: 'dist/server.js',
      cwd: path.join(__dirname, 'containers/video-export'),
      interpreter: 'node',
      autorestart: true,
      watch: false,
      max_memory_restart: '2500M',
      env: {
        NODE_ENV: 'production',
        PORT: 8088,
        LOCAL_APP_URL: 'http://127.0.0.1:3033',
      },
      log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
      error_file: path.join(__dirname, 'logs/openstory-export-error.log'),
      out_file: path.join(__dirname, 'logs/openstory-export-out.log'),
      merge_logs: true,
    },
  ],
};

3. Quy Trình Triển Khai Trên Máy Chủ

Bước 1: Chuẩn bị thư mục logs

cd ~/openstory
mkdir -p logs

Bước 2: Cài đặt & Cấu hình Xoay Vòng Logs (pm2-logrotate)

Nhằm ngăn chặn tình trạng file log phình to làm cạn kiệt dung lượng ổ cứng máy chủ:

# Cài đặt module pm2-logrotate
pm2 install pm2-logrotate

# Giới hạn kích thước mỗi file log tối đa 10MB
pm2 set pm2-logrotate:max_size 10M

# Tự động nén gzip (.gz) cho các file log cũ
pm2 set pm2-logrotate:compress true

# Lưu trữ tối đa 14 bản log gần nhất (tự động xóa log quá hạn)
pm2 set pm2-logrotate:retain 14

# Tự động cắt log mới hàng ngày vào lúc 00:00 đêm
pm2 set pm2-logrotate:rotateInterval '0 0 * * *'

Bước 3: Khởi động lại ứng dụng và lưu trạng thái

# Reload lại cấu hình ecosystem
pm2 restart ecosystem.config.cjs --update-env

# Lưu trạng thái danh sách tiến trình vào PM2 daemon
pm2 save

4. Hướng Dẫn Vận Hành & Tra Cứu Logs

4.1. Giám sát thời gian thực

  • Xem toàn bộ log:
    pm2 logs openstory
  • Chỉ xem luồng lỗi (stderr):
    pm2 logs openstory --err
  • Xem trực tiếp qua lệnh hệ thống tail:
    tail -f -n 100 ~/openstory/logs/openstory-error.log
    tail -f -n 100 ~/openstory/logs/openstory-out.log

4.2. Xử lý sự cố khi bị đụng port 3033

Nếu phát hiện lỗi Address already in use:

# 1. Dừng PM2
pm2 stop openstory

# 2. Kiểm tra tiến trình đang chiếm port 3033
sudo lsof -i :3033

# 3. Kill triệt để tiến trình workerd bị kẹt
pkill -9 -f workerd

# 4. Khởi động lại
pm2 start ecosystem.config.cjs --update-env