Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parallelized service starting and stopping tasks #4

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions defaults/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,29 @@ devture_systemd_service_manager_up_verification_enabled: true
#
# We can try to measure this gap and adjust our waiting time accordingly, but we currently don't.
devture_systemd_service_manager_up_verification_delay_seconds: 15

# devture_systemd_service_manager_parallel_service_setup_enabled controls whether systemd services should start/stop asynchronously.
# This could significantly reduce the duration for stopping/starting services depending on the number of services on the target host.
devture_systemd_service_manager_parallel_service_setup_enabled: false

# devture_systemd_service_manager_parallel_jobs specifies how many Ansible processes can run in parallel for the given task.
#
# Setting this value to 0 will run as many processes as possible at a time. Note that if this value is set to 0, you may
# need to increase your host(s) SSH configuration's `MaxSessions` property to facilitate all the connections that will be made in
# parallel. Additionally, you may need to increase the following parameters if all services cannot start before timing out:
# - ansible.cfg connection `timeout`
# - `devture_systemd_service_manager_up_verification_delay_seconds`
# - `devture_systemd_service_manager_parallel_async_timeout_seconds`
# - `devture_systemd_service_manager_parallel_job_status_retry_limit`
devture_systemd_service_manager_parallel_jobs: 16

# devture_systemd_service_manager_parallel_async_timeout_seconds specifies how long to wait before starting the job can timeout.
devture_systemd_service_manager_parallel_async_timeout_seconds: 60

# devture_systemd_service_manager_parallel_job_status_retry_limit specifies how many attempts the Ansible will check the status
# of the running jobs before failing the task.
devture_systemd_service_manager_parallel_job_status_retry_limit: 60

# devture_systemd_service_manager_parallel_job_status_retry_delay_seconds specifies how long Ansible will wait before it checks
# the status of the running jobs.
devture_systemd_service_manager_parallel_job_status_retry_delay_seconds: 1
38 changes: 25 additions & 13 deletions tasks/restart_specified.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,32 @@

- when: devture_systemd_service_manager_services_list_to_work_with | length > 1
block:
- name: Ensure systemd services are stopped
ansible.builtin.service:
name: "{{ item.name }}"
state: stopped
with_items: "{{ devture_systemd_service_manager_services_list_to_work_with | sort (attribute='priority,name', reverse=true) }}"
when: not ansible_check_mode
- when: not devture_systemd_service_manager_parallel_service_setup_enabled
block:
- name: Ensure systemd services are stopped
ansible.builtin.service:
name: "{{ item.name }}"
state: stopped
with_items: "{{ devture_systemd_service_manager_services_list_to_work_with | sort(attribute='priority,name', reverse=true) }}"
when: not ansible_check_mode

- name: Ensure systemd services are started
ansible.builtin.service:
name: "{{ item.name }}"
state: started
enabled: "{{ devture_systemd_service_manager_services_autostart_enabled }}"
with_items: "{{ devture_systemd_service_manager_services_list_to_work_with | sort (attribute='priority,name') }}"
when: not ansible_check_mode
- name: Ensure systemd services are started
ansible.builtin.service:
name: "{{ item.name }}"
state: started
enabled: "{{ devture_systemd_service_manager_services_autostart_enabled }}"
with_items: "{{ devture_systemd_service_manager_services_list_to_work_with | sort(attribute='priority,name') }}"
when: not ansible_check_mode

- when: devture_systemd_service_manager_parallel_service_setup_enabled
block:
- name: Ensure systemd services are stopped
ansible.builtin.include_tasks: "{{ role_path }}/tasks/stop_specified_async.yml"
when: not ansible_check_mode

- name: Ensure systemd services are started
ansible.builtin.include_tasks: "{{ role_path }}/tasks/start_specified_async.yml"
when: not ansible_check_mode

- when: devture_systemd_service_manager_service_restart_mode == 'one-by-one'
block:
Expand Down
40 changes: 27 additions & 13 deletions tasks/start.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,34 @@

- when: devture_systemd_service_manager_service_restart_mode == 'clean-stop-start'
block:
- name: Ensure systemd services are stopped
ansible.builtin.service:
name: "{{ item.name }}"
state: stopped
with_items: "{{ devture_systemd_service_manager_services_list | sort (attribute='priority,name', reverse=true) }}"
when: not ansible_check_mode
- when: not devture_systemd_service_manager_parallel_service_setup_enabled
block:
- name: Ensure systemd services are stopped
ansible.builtin.service:
name: "{{ item.name }}"
state: stopped
with_items: "{{ devture_systemd_service_manager_services_list | sort(attribute='priority,name', reverse=true) }}"
when: not ansible_check_mode

- name: Ensure systemd services are started
ansible.builtin.service:
name: "{{ item.name }}"
state: started
enabled: "{{ devture_systemd_service_manager_services_autostart_enabled }}"
with_items: "{{ devture_systemd_service_manager_services_list | sort (attribute='priority,name') }}"
when: not ansible_check_mode
- name: Ensure systemd services are started
ansible.builtin.service:
name: "{{ item.name }}"
state: started
enabled: "{{ devture_systemd_service_manager_services_autostart_enabled }}"
with_items: "{{ devture_systemd_service_manager_services_list | sort(attribute='priority,name') }}"
when: not ansible_check_mode

- when: devture_systemd_service_manager_parallel_service_setup_enabled
vars:
devture_systemd_service_manager_services_list_to_work_with: "{{ devture_systemd_service_manager_services_list }}"
block:
- name: Ensure systemd services are stopped
ansible.builtin.include_tasks: "{{ role_path }}/tasks/stop_specified_async.yml"
when: not ansible_check_mode

- name: Ensure systemd services are started
ansible.builtin.include_tasks: "{{ role_path }}/tasks/start_specified_async.yml"
when: not ansible_check_mode

- when: devture_systemd_service_manager_service_restart_mode == 'one-by-one'
block:
Expand Down
40 changes: 40 additions & 0 deletions tasks/start_specified_async.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---

# Suppress 'risky-shell-pipe' lint error due to the required fix `set -o pipefail` not being supported by all shells.
# Additionally, echo commands generally should not fail.
- name: Ensure systemd services are started
ansible.builtin.shell: >
echo "{{ devture_systemd_service_manager_services_list_to_work_with | sort(attribute='priority,name') | join(' ', attribute='name') }}"
|
xargs -P {{ devture_systemd_service_manager_parallel_jobs }} -d ' ' -I '{}'
ansible {{ inventory_hostname }} -i {{ inventory_file }} -m service {{ '' if become is undefined else '--become' }}
-a "
name={}
state=started
enabled={{ devture_systemd_service_manager_services_autostart_enabled }}
"
tags:
- skip_ansible_lint
register: "start_service_job_status"
delegate_to: localhost
become: false
async: "{{ devture_systemd_service_manager_parallel_async_timeout_seconds }}"
poll: 0
changed_when: false

- name: Check job status for started services
ansible.builtin.async_status:
jid: "{{ start_service_job_status.ansible_job_id }}"
register: start_service_job_status
until: start_service_job_status.finished
retries: "{{ devture_systemd_service_manager_parallel_job_status_retry_limit }}"
delay: "{{ devture_systemd_service_manager_parallel_job_status_retry_delay_seconds }}"
delegate_to: localhost
become: false

- name: Cleanup async job temp file
ansible.builtin.async_status:
jid: "{{ start_service_job_status.ansible_job_id }}"
mode: "cleanup"
delegate_to: localhost
become: false
7 changes: 6 additions & 1 deletion tasks/stop_specified.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,9 @@
ansible.builtin.service:
name: "{{ item.name }}"
state: stopped
with_items: "{{ devture_systemd_service_manager_services_list_to_work_with | sort (attribute='priority,name', reverse=true) }}"
with_items: "{{ devture_systemd_service_manager_services_list_to_work_with | sort(attribute='priority,name', reverse=true) }}"
when: not devture_systemd_service_manager_parallel_service_setup_enabled

- name: Ensure systemd services are stopped
ansible.builtin.include_tasks: "{{ role_path }}/tasks/stop_specified_async.yml"
when: devture_systemd_service_manager_parallel_service_setup_enabled
39 changes: 39 additions & 0 deletions tasks/stop_specified_async.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---

# Suppress 'risky-shell-pipe' lint error due to the required fix `set -o pipefail` not being supported by all shells.
# Additionally, echo commands generally should not fail.
- name: Ensure systemd services are stopped
ansible.builtin.shell: >
echo "{{ devture_systemd_service_manager_services_list_to_work_with | sort(attribute='priority,name', reverse=true) | join(' ', attribute='name') }}"
|
xargs -P {{ devture_systemd_service_manager_parallel_jobs }} -d ' ' -I '{}'
ansible {{ inventory_hostname }} -i {{ inventory_file }} -m service {{ '' if become is undefined else '--become' }}
-a "
name={}
state=stopped
"
tags:
- skip_ansible_lint
register: "stop_service_job_status"
delegate_to: localhost
become: false
async: "{{ devture_systemd_service_manager_parallel_async_timeout_seconds }}"
poll: 0
changed_when: false

- name: Check job status for stopped services
ansible.builtin.async_status:
jid: "{{ stop_service_job_status.ansible_job_id }}"
register: stop_service_job_status
until: stop_service_job_status.finished
retries: "{{ devture_systemd_service_manager_parallel_job_status_retry_limit }}"
delay: "{{ devture_systemd_service_manager_parallel_job_status_retry_delay_seconds }}"
delegate_to: localhost
become: false

- name: Cleanup async job temp file
ansible.builtin.async_status:
jid: "{{ stop_service_job_status.ansible_job_id }}"
mode: "cleanup"
delegate_to: localhost
become: false