Python django Gearman 实现web端发起任务,并显示出返回结果

  • 发布于: 14 May 2019
  • 编辑: 628财经

前言:

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>