实现异步非阻塞

docker下载redis
docker下载rabbitmq
docker run -d -p 5672:5672 rabbitmq
docker run -d -p 6379:6379 redis:alpine
docker exec -it 16e701cfb49b redis-cli
你的环境下下载
pip3 install celery
pip3 install rabbitmq
pip3 install redis
pip3 install django-debug-toolbar
在你的项目下创建一个celery.py的文件

image.png

写入如下代码

import os
from celery import Celery

# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'auto_cmdb.settings')

app = Celery('auto_cmdb')

# Using a string here means the worker doesn't have to serialize
# the configuration object to child processes.
# - namespace='CELERY' means all celery-related configuration keys
#   should have a `CELERY_` prefix.
app.config_from_object('django.conf:settings', namespace='CELERY')

# Load task modules from all registered Django app configs.
app.autodiscover_tasks()


再在settings里配置如下

# Celery 配置

# 配置消息中间件
CELERY_BROKER_URL = 'amqp://shark:123456@localhost:5672/lianjiu'
# 以上信息需要在 rabbitmq 中添加:
# 用户 shark  命令为: rabbitmqctl add_user shark 123456
# 虚拟主机 qfvhost 命令为: rabbitmqctl add_vhost qfvhost
# 授权信息  命令为: rabbitmqctl set_permissions -p qfvhost shark ".*" ".*" ".*"

# CELERY_RESULT_BACKEND = 'db+sqlite:///results.sqlite'
CELERY_RESULT_BACKEND = 'redis://localhost:6379/1'
# CELERY_TASK_SERIALIZER = 'json'


# 执行任务的异步工作进程/线程/绿色线程的数量。
# 如果您主要执行I / O,则可以有更多的进程,
# 但如果主要是CPU约束,请尝试使其与计算机上的CPU数量保持接近。
# 如果未设置,将使用主机上的CPU /内核数。
CELERY_WORKER_CONCURRENCY    = 6


# 延迟确认 意味着任务消息将在任务执行后得到确认
CELERY_TASK_ACKS_LATE = True

# 每个 worker 最多执行 60 个任务就自动销毁,防止内存泄露
CELERY_WORKER_MAX_TASKS_PER_CHILD = 60

# 单个任务的硬时间限制(秒)。
# 超过此值时,处理任务的工作进程将被终止并替换为新的工作进程。
CELERY_TASk_TIME_LIMIT = 5 * 60

######################################
# 配置 django-debug-toolbar

# 仅当IP地址列在“内部IP”设置中时,才会显示“调试”工具栏。
# 这意味着对于本地开发,必须将“127.0.0.1”添加到IntualIPS中;
# 如果在设置模块中不存在此设置,则需要创建此设置:
INTERNAL_IPS = [
    '127.0.0.1',
]

DEBUG_TOOLBAR_CONFIG = {
    # Toolbar options
    'RESULTS_CACHE_SIZE': 3,
    'SHOW_COLLAPSED': True,
    # Panel options
    'SQL_WARNING_THRESHOLD': 0.5,   # milliseconds 毫秒
}

这是用来连接redis的 rabbitmqctl是一个连接redis的中间件

之后在项目下创建tasks.py文件 (不能改)
在tasks里边写要并发的函数之类的

from __future__ import absolute_import, unicode_literals
from celery import shared_task
from .utils.handle_commend import HandleCommand
from cmdb.models import InventoryPool
import time 

@shared_task
def cmdb_celery(command):
        inventorys = InventoryPool.objects.all()
        handle = HandleCommand(command,inventorys)
        ret = handle.exec_command()
        print("任务执行中")
        return ret

@shared_task
def add(n):
    import time
    time.sleep(8)
    return n + 1

之后在对应的视图导入

from .tasks import cmdb_celery,add

class AsyncView(View):
    def get(self,request):
        return render(request,'octopus/async.html')
    
    def post(self,request):
        num = request.POST.get("num")
        task = add.delay(int(num))
        print("命令已送达。。。。。。。")
        return JsonResponse({"task_id":task.id}) 
第二个例子
class RunViewajax(View):
    def get(self,request):
        inventorys = InventoryPool.objects.all()
        return render(request,"octopus/run1.html",{
            "inventorys":inventorys
        })
    def post(self,request):
        
        command= request.POST.get('command')
        task1 = cmdb_celery.delay(command)
        

要用delay才能实现异步 并且他自己可以实现一个ID这样.出来就行
下面实现传入前端的数据

from celery.result import AsyncResult
class TaskResultView(View):
    def get(self, request):
        task_id = self.request.GET.get("task_id")
        task_obj = AsyncResult(id=task_id)
        task_json = {
            "id": task_obj.id,
            "status": task_obj.status,
            "success": task_obj.successful(),
            "result": task_obj.result
        }
        return JsonResponse(task_json)

前端实例

{% load staticfiles %}
{% block first%}
ansible 执行命令
{% endblock %}
{% block second %}run
{% endblock %}
{% block content %}


    <div class="row">
      <div class="col-md-3">
        <h3>组列表</h3>
            {% for  inventory in  inventorys %}
        <div class="box box-solid collapsed-box">
          <div class="box-header with-border">
            <h3 class="box-title">{{  inventory.group }}</h3>

            <div class="box-tools">
              <button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-plus"></i>
              </button>
            </div>
          </div>
          <div class="box-body no-padding" style="display:  none">
            <ul class="nav nav-pills nav-stacked">
                            {% for server in inventory.server.all %}
              <li><a href="#"><i class="fa fa-laptop"></i> {{ server.manager_ip }}</a></li>
            {% endfor %}
            </ul>

          </div>
          <!-- /.box-body -->
        </div>
        {% endfor %}
       
        <!-- /.box -->
      </div>
      <!-- /.col -->
      <div class="col-md-9">
            <div class="box box-primary">
              <div class="box-header with-border">
                <h3 class="box-title">执行 Ansible 命令</h3>
  
              </div>
              <!-- /.box-header -->
              
              <!-- /.box-body -->
              <div class="box-footer no-padding">
                <div class="box-footer">
                
                        <div class="input-group">
                        <input type="text" name="command" placeholder="ansible all -m shell -a  'ls /tmp'" style="font-size: 30px;height: 50px" class="form-control">
                            <span class="input-group-btn" >
                              <button type="submit" class="btn btn-success" id="sendinfo">Send</button>
                            </span>
                      </div>
                  </div>
              </div>
            </div>
            <!-- /. box -->
            <div class="box box-primary">
                <div class="box-header with-border">
                  <h3 class="box-title">命名结果展示</h3>
                </div>
                <div class="box-footer no-padding" >
                    <span  id="result"></span>
                </div>

                    
            </div>

        </div>
        </div>

 

{% endblock %}


{% block script %}
<script>
    $(function(){  
     function handleTask(task_id){
            var timer = setTimeout(function f(task_id) {
                // 根据 task_id 获取 task 对象
                $.getJSON(
                    url=`/octopus/get_task/?task_id=${task_id}`,
                    function(ret){
                        if (ret.success){
                            $("#result").append(`<div><code >${ret.id}</code><div>`)
                            $("#result").append(`<div><code >${ret.status}</code><div>`)
                            $("#result").append(`<div><code >任务结果${ret.result.msg}</code><div>`);
                            clearTimeout(timer);
                        }else{
                            $("#result").append(`<div><code >${ret.id}</code><div>`);
                            $("#result").append(`<div><code >${ret.status}</code><div>`);
                        };
                    }
                )
                timer = setTimeout(f, 2000, task_id);
              }, 2000, task_id);
        }


    $("#sendinfo").on("click", function(){
        let command = $(this).parent().siblings().val();
        if( !command){
          alert("命令为空");
          return false
        }

        $.ajax({
            url: "{% url 'octopus:run' %}",
            type: "POST",
            data: {"command": command,'csrfmiddlewaretoken':'{{ csrf_token }}'},
            dataType:'json',
            success: function(res){
                        $("#commandResult").empty();
                        let task_id = res.task_id;
                        // alert("task_id");
                        // $("#result").text(task_id);
                        handleTask(task_id);
                    }
            }
        )
        
      }) 
      })
</script>
{% endblock %}
前端中要注意的是定时期JS
延迟多少事件后在执行一个函数
setTimeout(function(形参){},2000,实参)//毫秒
-每隔多长时间执行一次函数
setInventory(function(形参){},2000,实参)

clearTimeout(timer)清除定时器


url


image.png

运行这个celery
celery -A auto_cmdb worker -l info

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,924评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,781评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,813评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,264评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,273评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,383评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,800评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,482评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,673评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,497评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,545评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,240评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,802评论 3 304
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,866评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,101评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,673评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,245评论 2 341

推荐阅读更多精彩内容