Python django Gearman 实现web端发起任务,并显示出返回结果
前言:
Gearman是一个很好用的轻量级工具,他的作用是帮你在服务器上执行任务,并回调给任务发起者,一般可用于视频转码,数据收集等领域,因为gearman不支持任务找回,如果服务器意外重启或程序挂掉,那么之前提交的未完成的任务就需要重新提交,所以不太适合做精确度高的项目。
Python+Django+Gearman 可以很容易的帮助运维将服务器上的操作搬到web中执行,方便运维本身,也可以在合理权限内让更多人参与维护,减轻运维工作压力。
本文将按照作者本人的理解来阐述,如有不对之处欢迎指正。
Gearman工作原理:
Gearman更像是一个任务管理器,他分为server端,client端,以及worker端三个部分。server端负责接收任务,并将任务指派给worker端,client端只负责提交任务,worker端只负责处理任务,三方各干各的活。
本文只介绍怎样通过web端提交任务,并将结果返回给使用者(网民)。其中发起提交行为的web端相当于client端,这里的client端不是网民而是提交程序(Django)本身。
搭建Server端:
Server端可以在任意与Django所在服务器互通的机器上部署,本身没有系统消耗的压力,也可以部署在Django服务上,只要稳定就好。
首先安装gearman:(如果安装不上可以自行搜索其他方法)
yum install gearmand
开启server端服务:(开启后通过 netstat -tunlp 查看端口是否存在,存在即成功开启)
gearmand -p 4730 -L 0.0.0.0 --log-file=/tmp/gearmand-4730.log --pid-file=/tmp/gearmand-4730.pid -d
编写worker端:
worker一般部署在具体执行任务的机器上,比如我们要做一个查询系统,那么一般将worker部署到执行查询脚本的机器上,可以非root权限;
#!/usr/bin/python # -*- coding: utf-8 -*- import subprocess, datetime, os, time, signal import gearman gm_worker = gearman.GearmanWorker(['10.11.12.13:4730']) #先把worker登记到server端,此处填写server端地址+端口 def data_import(gearman_worker, gearman_job): #gearman_worker为注册的任务名称,gearman_job为client端提交过来的任务指令 if gearman_job.data.startswith(('show','newshow')): #此处为了操作安全,限制了操作命令,只允许show或newshow开头的命令执行 sed = " | sed -r 's/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g' | sed '/^start=/d' | sed -r '/^cdn.*\-{10}/d '" #此处通过sed对将要执行后的数据做一些格式上的替换,如果没有相关需求,可忽略 cmd = gearman_job.data + sed #要执行的命令 shdata = subprocess.check_output(cmd,shell=True) #以shell形式执行cmd指令,并将结果传递给变量shdata return shdata else: return '非法操作' gm_worker.set_client_id('worker_001') #定义worker的名称,如果有多台服务器,可以让每台机器使用不同的名称 gm_worker.register_task('data_import', data_import) #注册任务,格式为‘任务名称’,任务函数名 gm_worker.work()
这样一个简单的worker就写好了,他的作用是等待client端提交名为show或newshow的任务过来执行,并返回执行后得到的数据。
worker可以开启到后台或者screen中,可以多开几个进程,也可以部署在多台机器上,gearman会按照进程个数来分配任务,例如:
nohup python ./gearman-worker.py &
Client端参考:
... cmd = 'newshow' #要执行的命令 gm_client = gearman.GearmanClient(['localhost:4730']) #声明server端信息,注意这里是将server部署到本地了 exeStartTime = datetime.datetime.now() #调试 调取gearman开始时间 exeEndTime = datetime.datetime.now() #调试 调取gearman结束时间 print('StartTime:',exeStartTime) #调试 查看执行时间情况 completed_job_request = gm_client.submit_job("data_import",str(cmd)) #向worker提交任务,data_import 是任务名称 对应着worker里注册的任务名称 List = completed_job_request.result #gearman的返回结果是一个list数据结构,此处将返回结果保存到List print List #调试打印出返回结果 ...
以上就是一个简单的client端提交逻辑,可以对该结果直接显示
return render (request,'test/test.html',{'List':List})
当然为了对页面更加友好,建议将gearman返回的数据整理成json格式,这样可以在django页面中通过for循环逐一显示在table中,具体可以参考“自强学堂”中的教程。
页面参考:
<div class="table-responsive"><!--响应式布局--> <table align="left" width="928" class="table table-bordered table-hover"> <thead> <tr> <th>回源状态码</th> <th>数量</th> <th>该状态码总量</th> <th>状态码占比</th> <th>全量占比</th> </tr> </thead> <tr> {% for UpstreamStatus in json_list.UpstreamStatus %} <td>{{ UpstreamStatus.UpstreamStatus }}</td> <td>{{ UpstreamStatus.count }}</td> <td>{{ UpstreamStatus.all_given_httpcodecnt}}</td> <td>{{ UpstreamStatus.request_percentage }}</td> <td>{{ UpstreamStatus.all_request_percentage }}</td> </tr> {% endfor%} </table> </div>