异步功能不作为单独的模块出现,而是作为任务参数使用,因此,大多数模块都可以异步执行;
异步执行功能通常是用来解决执行任务时间过长导致SSH连接超时。
示例:
--- - hosts: "ansible-server" tasks: - name: simulate long running op (15 sec), wait for up to 45 sec, poll every 5 sec command: /bin/sleep 15 async: 45 poll: 5
async
任务最大执行时间
poll
轮询间隔
> POLL:
当 poll > 0 的时候,任务本身依然会阻塞运行,但是,实际上ansible任务与内部执行的shell脚本之间是异步执行,在脚本执行过程中,ansible任务会根据poll设置的轮询时间间隔取获取脚本执行的状态,并根据async判断是否超时了;举个例子:
这是剧本,超时时间设置的很大,轮询间隔是20s,即每20秒获取一次执行状态;
--- - hosts: "ansible-server" tasks: - name: test for sync job shell: | cd ~/scripts sh sleep.sh async: 999 poll: 20这是sleep.sh脚本,睡眠5s;
sleep 5s执行结果是整个任务依然需要等待大约20s才能执行完成(虽然实际上有效工作时间只有5s);
当 poll = 0 的时候,任务本身实现了非阻塞的异步执行,由于没有轮询间隔,代表着该任务本身并不会主动获取任务执行状态和结果;此时异步任务会一直执行,直到完成、失败或超时;
我们举个例子:
这是剧本,这次设置poll参数为0,这意味着这个任务是异步执行的,也就是,一旦开启了这个任务,剧本就会退出;
--- - hosts: "ansible-server" tasks: - name: test for sync job shell: | cd ~/scripts sh sleep.sh async: 999 poll: 0这是sleep.sh脚本,在睡眠20s后,会创建一个时间戳文件;
sleep 20s mkdir `date +%H%M%S`.txt我们运行剧本,发现几乎在启动的同时剧本就执行完成了,而等待20s左右,在sleep.sh同级目录下生成了一个.txt文件;这说明异步执行的任务即使剧本退出,也会继续执行下去;
异步功能本身无法自身向用户反馈执行状态和结果,如果要异步执行任务并稍后进行检查,可以使用async_status模块进行监控与反馈;
示例:
--- # Requires ansible 1.8+ - name: 'YUM - async task' yum: name: docker-io state: present async: 1000 poll: 0 register: yum_sleeper - name: 'YUM - check on async task' async_status: jid: "{{ yum_sleeper.ansible_job_id }}" register: job_result until: job_result.finished retries: 30 delay: 5
2.1. 参数
参数名
jid
作业或任务标识符
mode
如果为status,则获取状态
如果是cleanup,清理指定的作业jid异步作业缓存(~/.ansible_async/)
2.2. 返回值
返回值名
ansible_job_id
异步任务的id
finished
异步任务是否完成(1:已完成;0:未完成)
started
异步任务是否开始(1:已开始;0:未开始)
获取异步任务执行状态通常可以与until参数配置使用,在可控制的次数内,不断地取查询任务执行状态,直到任务执行结束、失败或超时;
2.3. Until条件循环
简单介绍一下until循环参数:
until
条件终止表达式
retries
最大循环次数
delay
每次循环时间间隔(秒)
循环终止有两个条件,任意满足其一就可以:
1. 循环次数超过最大次数;
2. 满足until条件,直接跳出循环;
综合举个例子:
剧本如下:
--- - hosts: "ansible-server" tasks: - name: test for sync job shell: | sleep 15 async: 999 poll: 0 register: sleeper - name: Monitor and feedback async_status: jid: "{{ sleeper.ansible_job_id }}" register: backer until: backer.finished retries: 20 delay: 1一个睡眠15秒的异步任务,为任务本身注册一个变量sleeper;
一个监控任务,输入jid为监控对象的id,利用Until循环,条件为输出数据的finished字段,设置的最大循环次数为20,循环间隔时间为1秒;
输出日志打印:
[WARNING]: Invalid characters were found in group names but not replaced, use -vvvv to see details PLAY [ansible-server] *************************************************************************************** TASK [Gathering Facts] ************************************************************************************** ok: [localhost] TASK [test for sync job] ************************************************************************************ changed: [localhost] TASK [Monitor and feedback] ********************************************************************************* FAILED - RETRYING: Monitor and feedback (20 retries left). FAILED - RETRYING: Monitor and feedback (19 retries left). FAILED - RETRYING: Monitor and feedback (18 retries left). FAILED - RETRYING: Monitor and feedback (17 retries left). FAILED - RETRYING: Monitor and feedback (16 retries left). FAILED - RETRYING: Monitor and feedback (15 retries left). FAILED - RETRYING: Monitor and feedback (14 retries left). FAILED - RETRYING: Monitor and feedback (13 retries left). FAILED - RETRYING: Monitor and feedback (12 retries left). FAILED - RETRYING: Monitor and feedback (11 retries left). FAILED - RETRYING: Monitor and feedback (10 retries left). FAILED - RETRYING: Monitor and feedback (9 retries left). changed: [localhost] PLAY RECAP ************************************************************************************************** localhost : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0如图所示,大概在循环11次的时候满足Until条件(任务之间有时间间隔造成的误差),跳出循环,结束执行;
设workflow.sh脚本执行时间久,为了保持jenkins服务器与部署服务器保持连接(设置未通信状态下超时时间为15分钟),则希望不断返回日志;
方式一:使用异步任务执行+async_status模块
- name: 执行脚本 shell: | . ~/.profile && sh workflow.sh > workflow.log args: chdir: ~/ async: 1 poll: 0 register: work_stat - name: 监控状态 async_status: jid={{ work_stat.ansible_job_id }} register: task_result until: task_result.finished retries: 20 delay: 10注意:某些脚本如果没有显式退出程序,则永远不会执行完成;
方式二:使用nohup异步+Until轮询进程
剧本如下:
- name: 执行脚本 shell: | . ~/.profile && nohup sh workflow.sh > workflow.log 2>&1 & args: chdir: ~/ ignore_errors:True - name: 监控进程 shell: | ps -ef | grep workflow | grep -v grep | wc -l register: processStatus until: processStatus.stdout|int < 1 retries:20 delay: 10 ignore_errors: True