Lỗi Gặp Phải
Bạn khởi động một tác vụ chạy lâu với async và poll: 0, sau đó dùng async_status để thu thập kết quả. Thay vì thành công, bạn nhận được thông báo này:
FAILED! => {"msg": "Timeout (30s) waiting for async task to finish", "finished": 0, "started": 1}
"finished": 0 là chi tiết mấu chốt — tác vụ vẫn đang chạy khi async_status bỏ cuộc. Nó khởi động bình thường. Chỉ là cần nhiều thời gian hơn bạn đã cấp.
Nguyên Nhân
Với poll: 0, Ansible kích hoạt tác vụ rồi chuyển sang ngay lập tức. Không chờ đợi. Sau đó, async_status kiểm tra kết quả bằng cách lặp với retries và delay. Timeout xảy ra khi một trong hai trường hợp sau xảy ra:
- Ngân sách
retries × delaycạn kiệt trước khi tác vụ hoàn thành. - Bản thân giá trị
asyncquá nhỏ — Ansible sẽ tắt tiến trình từ xa sau số giây đó.
Đây là vòng lặp polling mặc định bạn thấy trong hầu hết các playbook. Tính thử: 10 lần thử × 3 giây = tổng 30 giây. Ổn với một script nhanh, nhưng sẽ không đủ cho việc cài gói, migration cơ sở dữ liệu, hay bất cứ thứ gì thực sự tốn thời gian.
- async_status:
jid: "{{ async_result.ansible_job_id }}"
register: job_result
until: job_result.finished
retries: 10
delay: 3 # 10 × 3 = 30 seconds total wait
Cách Khắc Phục Từng Bước
Bước 1 — Đo thời gian thực tế tác vụ của bạn chạy mất bao lâu
SSH vào máy chủ từ xa và đo trực tiếp:
time apt-get install -y some-large-package
# or
time ./long_migration_script.sh
Lấy con số đó và cộng thêm 50–100% dự phòng. Một tác vụ chạy trong 3 phút trên máy nhanh có thể mất 6 phút trên máy chủ quá tải lúc 2 giờ sáng. Hãy tính cho trường hợp xấu nhất.
Bước 2 — Đặt async đủ cao
async là bộ đếm thời gian kill cứng trên máy chủ từ xa. Khi đã hết số giây đó, Ansible sẽ kết thúc tiến trình — dù nó sắp hoàn thành hay chưa. Hãy đặt giá trị này cao hơn rõ rệt so với thời gian chạy xấu nhất của bạn:
- name: Run long database migration
command: /opt/app/migrate.sh
async: 600 # allow up to 10 minutes
poll: 0
register: migration_job
Bước 3 — Sửa vòng lặp polling của async_status
Tăng retries và delay sao cho tích của chúng bằng (hoặc vượt) giá trị async của bạn:
- name: Wait for migration to complete
async_status:
jid: "{{ migration_job.ansible_job_id }}"
register: job_result
until: job_result.finished
retries: 60 # check up to 60 times
delay: 10 # every 10 seconds = 600 seconds total
Quy tắc rất đơn giản: retries × delay phải ≥ async. Nếu vòng lặp polling bỏ cuộc trước, bạn sẽ gặp lỗi timeout dù tác vụ vẫn đang chạy bình thường trên máy chủ từ xa.
Ví dụ hoàn chỉnh
---
- hosts: app_servers
tasks:
- name: Run package upgrade (long task)
apt:
upgrade: dist
async: 900 # 15-minute hard cap on remote
poll: 0
register: apt_job
- name: Wait for package upgrade
async_status:
jid: "{{ apt_job.ansible_job_id }}"
register: apt_result
until: apt_result.finished
retries: 90 # 90 × 10s = 900s — matches async value
delay: 10
- name: Show upgrade result
debug:
var: apt_result
Bước 4 — Bỏ qua tất cả những bước này nếu bạn không cần kiểu "bắn rồi quên"
Kiểu "bắn rồi quên" với poll: 0 chỉ hữu ích khi bạn cần khởi động nhiều tác vụ chạy lâu song song, hoặc làm việc khác trong khi chờ tác vụ chậm hoàn thành. Với một tác vụ chạy lâu đơn lẻ, chỉ cần bỏ poll: 0 và để Ansible tự xử lý việc polling:
- name: Run long task with built-in polling
command: /opt/app/migrate.sh
async: 600
poll: 15 # Ansible checks every 15 seconds, no async_status needed
Ít thành phần hơn, kết quả như nhau.
Xác Minh Bản Sửa
Chạy với -v để theo dõi quá trình polling theo thời gian thực:
ansible-playbook site.yml -v
Bạn sẽ thấy các dòng như thế này trong khi tác vụ chạy:
ASYNC POLL on host1: jid=..., started=1, finished=0
ASYNC POLL on host1: jid=..., started=1, finished=0
ASYNC OK on host1: jid=..., finished=1, rc=0
finished=1, rc=0 nghĩa là thành công. Vẫn bị timeout? Hãy tăng retries và chạy lại. Nếu timeout ngay lập tức, hãy kiểm tra lại xem giá trị async của bạn có phải là điểm nghẽn không.
Bạn cũng có thể kiểm tra tác vụ trực tiếp trên máy chủ từ xa — Ansible ghi các file async job tại đây:
ls ~/.ansible_async/
cat ~/.ansible_async/<jid>
Tham Khảo Nhanh: async vs poll vs async_status
- async: N — Bộ đếm thời gian kill cứng trên máy chủ từ xa. Tiến trình sẽ bị kết thúc sau N giây, dù đã xong hay chưa.
- poll: 0 — Bắn rồi quên. Bạn chịu trách nhiệm thu thập kết quả bằng
async_status. - poll: N (N > 0) — Ansible tự động polling mỗi N giây. Không cần
async_status. - retries × delay — Phải ≥
async, nếu không vòng lặp polling của bạn sẽ hết thời gian trước.
Mẹo Hay
- Chỉ dùng
poll: 0khi bạn thực sự cần thực thi song song — chạy nhiều tác vụ chậm đồng thời trên nhiều host, hoặc làm việc khác trong khi chờ. Nếu không, polling tích hợp sẽ gọn gàng hơn. - Lưu job ID ngay sau khi khởi động tác vụ async. Nếu play bị crash trước khi
async_statuschạy, bạn vẫn có thể kiểm tra thủ công trên máy chủ từ xa bằng jid từ~/.ansible_async/. - Nhận được
"failed": truetừasync_status? Đó không phải timeout — tác vụ đã hoàn thành nhưng trả về exit code khác không. Kiểm trajob_result.stderrđể tìm lỗi thực sự. - Người dùng Ansible Tower / AWX: Tower có cài đặt timeout riêng cho job, tách biệt với giá trị
async. Một tác vụ có thể bị Tower kết thúc trước khi bộ đếmasyncphía từ xa kích hoạt. Hãy đảm bảo cả hai đều được cấu hình với đủ thời gian dự phòng.

