Sửa lỗi vòng lặp 'until' trong Ansible: Giải quyết lỗi Retry 'non-zero return code'

intermediate🔧 Ansible2026-07-09| Ansible 2.9+, Linux (Ubuntu, CentOS, RHEL) và các môi trường Cloud như AWS hoặc Azure.

Error Message

FAILED! => {"attempts": 5, "changed": false, "msg": "non-zero return code"}
#ansible#devops#automation#troubleshooting#linux

Sự cố Pipeline lúc 2 giờ sángĐã khuya, và bạn đang đẩy một bản sửa lỗi khẩn cấp (hotfix) quan trọng lên một microservice môi trường production. Playbook Ansible bắt đầu mượt mà nhưng đột nhiên bị treo trong quá trình kiểm tra sức khỏe (health check). Sau 60 giây im lặng đáng sợ, terminal của bạn bùng nổ với một khối thông báo lỗi màu đỏ ANSI:

FAILED! => {"attempts": 5, "changed": false, "msg": "non-zero return code"}

Lỗi này xảy ra khi bạn sử dụng từ khóa until để thăm dò (poll) một tài nguyên và Ansible đạt đến giới hạn retries. Về cơ bản, lệnh bên trong vòng lặp của bạn liên tục thất bại, hoặc điều kiện thành công của bạn không bao giờ trở thành đúng trước khi hết thời gian chờ.

Tại sao điều kiện 'until' của bạn bị đình trệAnsible đánh giá cả sự thành công của module và logic until tùy chỉnh của bạn trong mỗi lần lặp. Thông thường, một trong ba vấn đề sau đang xảy ra:

  • Khoảng cách thành công (The Success Gap): Dịch vụ của bạn mất 90 giây để khởi tạo, nhưng vòng lặp của bạn chỉ đợi trong 50 giây. Tác vụ không bị hỏng; nó chỉ là không đủ kiên nhẫn.- Khoảng trắng ẩn: Bạn đang kiểm tra stdout cho từ "ready", nhưng hệ thống thực tế lại trả về "ready\n". Ký tự xuống dòng đơn lẻ đó sẽ làm hỏng việc so sánh chuỗi mọi lúc.- Bẫy Shell: Khi sử dụng module shell, bất kỳ mã thoát khác không (non-zero exit code) nào (như lỗi 404 từ curl) đều khiến Ansible coi lần thử đó là thất bại, ngay cả khi bạn có ý định đợi mã 200 OK.## Giải pháp: Logic thăm dò thông minh hơn### 1. Xử lý các lỗi lệnh tạm thờiNếu bạn sử dụng curl để kiểm tra một API đang khởi động, bản thân lệnh đó sẽ trả về mã lỗi cho đến khi cổng được mở. Bạn phải đảm bảo vòng lặp tiếp tục ngay cả khi lệnh thất bại. Mặc dù until tự động thử lại khi thất bại, việc sử dụng module uri sẽ sạch sẽ hơn nhiều so với các lệnh shell thô.
- name: Đợi API Spring Boot báo cáo trạng thái UP
  uri:
    url: "http://localhost:8080/actuator/health"
    status_code: 200
  register: api_result
  until: api_result.status == 200
  retries: 20
  delay: 10

# Dành cho các script shell cũ:
- name: Kiểm tra trạng thái dịch vụ cũ
  shell: "/opt/bin/check_app_status.sh"
  register: shell_out
  until: shell_out.rc == 0
  retries: 15
  delay: 5
  failed_when: false # Ngăn tác vụ bị dừng đột ngột trước khi kết thúc các lượt thử lại

2. Debug với khả năng hiển thị caoNếu điều kiện của bạn có vẻ đúng nhưng vẫn thất bại, bạn cần xem chính xác những gì Ansible thấy. Một sai lầm phổ biến là giả định stdout là một chuỗi sạch. Sử dụng bộ lọc trim hoặc kiểm tra search để làm cho logic của bạn linh hoạt hơn trước các khoảng trắng thừa hoặc dấu thời gian trong log.

- name: Đợi log xác nhận 'Database Migration Complete'
  shell: tail -n 5 /var/log/deploy.log
  register: log_check
  # Sử dụng search an toàn hơn so với so khớp chuỗi chính xác
  until: log_check.stdout is search("Complete")
  retries: 12
  delay: 10

3. Hiệu chỉnh khoảng thời gian thăm dò (Polling Window)Phép toán rất quan trọng ở đây. Nếu một quá trình di chuyển cơ sở dữ liệu nặng mất 5 phút để chạy, nhưng tác vụ Ansible của bạn sử dụng retries: 5delay: 10, bạn chỉ mới cho phép 50 giây đệm. Luôn tính toán kịch bản tệ nhất và thêm 20% biên độ an toàn.

- name: Đợi di chuyển DB nặng (Tối đa 6 phút)
  command: /usr/bin/verify_db_schema.sh
  register: db_status
  until: db_status.rc == 0
  # 36 lần thử * 10 giây trễ = 360 giây
  retries: 36
  delay: 10

Xác minh: Xác nhận giải phápChạy playbook của bạn với cờ -v để theo dõi các lần thử trong thời gian thực. Bạn sẽ thấy bộ đếm thử lại tăng dần mà playbook không dừng lại:

FAILED - RETRYING: Wait for API (20 retries left).
FAILED - RETRYING: Wait for API (19 retries left).
...
changed: [app_server] => {"attempts": 12, "changed": true, "status": 200}

Nếu tác vụ cuối cùng chuyển sang màu xanh, thời gian và logic của bạn đã đồng bộ. Nếu nó chạm đến lần thử thứ 36 và vẫn thất bại, vấn đề nằm ở dịch vụ ứng dụng của bạn, không phải ở mã Ansible.

Các phương pháp hay nhất cho vòng lặp ổn định- Ưu tiên wait_for: Sử dụng module wait_for để kiểm tra xem một cổng có mở hay không trước khi chạy các vòng lặp until phức tạp. Nó nhanh hơn và sử dụng ít tài nguyên hơn.- Kiểm tra mã trả về (Return Codes): Kiểm tra until: result.rc == 0 hầu như luôn đáng tin cậy hơn việc phân tích cú pháp các chuỗi stdout.- Làm sạch chuỗi: Nếu bạn phải khớp văn bản, hãy sử dụng | trim để loại bỏ các ký tự xuống dòng ẩn gây ra lỗi so sánh.- Tránh ignore_errors: Đừng sử dụng ignore_errors: yes như một giải pháp tạm thời. Nó che giấu các thất bại thực sự. Thay vào đó, hãy sử dụng failed_when hoặc tinh chỉnh điều kiện until của bạn.

Related Error Notes