Blog #19

Deploy with downtime is zero

DATPMT Mar 25 2024 Tag icon
#Nginx
#Puma

# Reason

Hãy tưởng tượng bạn đang sở hữu một API production có lượng requests bất kể ngày đêm, giờ giấc và bạn cần deploy để update một vài thay đổi. Trong khi deploy thì Puma có cơ chế kill current puma.sock và tạo ra một puma.sock mới.

Vậy thì có liên quan gì???  

Khi một request được gửi tới server thì Nginx sẽ hứng request đó và gửi đến puma.sock. Vậy khi request gửi trong khi Puma restart thì sao? Thì error 502 chứ sao  

Nó làm gián đoạn server và người dùng sẽ bị ức chế. Kiểu như wtf sao tao đang chạy mà bị lỗi, debug các kiểu xong mới phát hiện ra à là do cái thằng API kia bị lỗi. Vậy thì sẽ giảm chất lượng dịch vụ của bạn đúng không? Rồi dần dần đ*o ai thèm dùng dịch vụ của bạn luôn @@

Trước đây khi chưa biết cơ chế này mình rất ngại deploy, phải kiếm khung giờ mà ít người dùng nhất và cầu trời đừng có request nào gửi tới khi deploy , kiểu như lén lút deploy vậy :D. Thôi bắt đầu cùng mình giải quyết vấn đề nào.  

# Getting started

Puma restart mất đâu đó khoảng 0.1s → hơn 1s chút (đó là đối với các server của mình, các bạn có thể cao hơn)

Vậy chúng ta sẽ bắt Nginx chờ 10s sau khi Puma restarted vậy là oke :v

À quên trước khi bắt đầu thì phải cài đặt các nginx modules thích hợp nha, ở đây chúng ta cần ngx_http_echo_module

$ sudo apt-get install nginx-extras

Gói này bao gồm các modules bổ sung, bao gồm ngx_http_echo_module.

Cấu hình nginx lại như sau:

server {
    server_name xxx;
    root xxx;
    
    # Try serving static files first, then pass to the application
    try_files $uri/index.html $uri @app;
    # Main location block for proxying requests to the application
    location / {
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $host;
        proxy_redirect off;
        proxy_set_header Connection '';
        proxy_pass upstreams_name;
        # Retry requests and handle errors
        proxy_intercept_errors on;
        error_page 502 @delay;
    }
    # Delayed location block for retrying requests
    location @delay {
        proxy_pass upstreams_name;
        echo_sleep 10;  # Delay for 10 seconds
    }
}

Mình thì để 10s cho an toàn :v các bạn tuỳ chỉnh theo nhu cầu là được.

Reload Nginx:

$ sudo systemctl reload nginx

Vậy là xong rồi nha :D. Giờ đây mình không cần phải lén lút deploy nữa mà chỉ cần lén lút fix bugs rồi deploy mà không một ai biết