--- # roles/upgrade/tasks/main.yml # # Async pattern: Tailscale may restart during upgrade, dropping SSH. # Fire and forget → poll status with unreachable tolerance + retries. - name: Upgrade all packages (Alpine) community.general.apk: upgrade: true update_cache: true async: 3600 poll: 0 register: upgrade_alpine_job # By default async job return change: true # Force adapting the change condition for idempotency changed_when: false when: ansible_facts['os_family'] == "Alpine" - name: Wait for Alpine upgrade ansible.builtin.async_status: jid: "{{ upgrade_alpine_job.ansible_job_id }}" register: upgrade_alpine_result until: upgrade_alpine_result.finished retries: 60 delay: 10 # By default async job return change: true # Force adapting the change condition for idempotency changed_when: upgrade_alpine_result.changed | default(false) ignore_unreachable: true when: - ansible_facts['os_family'] == "Alpine" - upgrade_alpine_job.ansible_job_id is defined - name: Upgrade all packages (Debian) ansible.builtin.apt: upgrade: full update_cache: true async: 3600 poll: 0 register: upgrade_debian_job # By default async job return change: true # Force adapting the change condition for idempotency changed_when: false when: ansible_facts['os_family'] == "Debian" - name: Wait for Debian upgrade ansible.builtin.async_status: jid: "{{ upgrade_debian_job.ansible_job_id }}" register: upgrade_debian_result until: upgrade_debian_result.finished retries: 60 delay: 10 # By default async job return change: true # Force adapting the change condition for idempotency changed_when: upgrade_debian_result.changed | default(false) ignore_unreachable: true when: - ansible_facts['os_family'] == "Debian" - upgrade_debian_job.ansible_job_id is defined