2016-03-14 31 views
1

我正在嘗試使用龍捲風的異步功能。到目前爲止,我只獲得了一點成功。我正在使用我發現的here的修改版本來協助我的異步..也許這不是最好的方法,你告訴我你的想法或者是否有更好的方法。這裏是我用來幫助我的異步請求的subprocess_helper.py文件。如何發送來自異步龍捲風發佈請求的響應以在html模板上呈現?

import tornado.process 
import subprocess 
import logging 

from tornado.gen import Task, Return, coroutine 
from tornado.ioloop import IOLoop 

STREAM = tornado.process.Subprocess.STREAM 
@coroutine 
def call_subprocess(cmd, stdin_data=None, stdin_async=False): 
    """ 
    Wrapper around subprocess call using Tornado's Subprocess class. 
    """ 
    stdin = STREAM if stdin_async else subprocess.PIPE 

    sub_process = tornado.process.Subprocess(
     cmd, stdin=stdin, stdout=STREAM, stderr=STREAM 
) 

    if stdin_data: 
     if stdin_async: 
      yield Task(sub_process.stdin.write, stdin_data) 
     else: 
      sub_process.stdin.write(stdin_data) 

    if stdin_async or stdin_data: 
     sub_process.stdin.close() 

    result, error = yield [ 
     Task(sub_process.stdout.read_until_close), 
     Task(sub_process.stderr.read_until_close) 
    ] 

    raise Return((result, error)) 


def on_timeout(): 
    logging.info("timeout") 
    #IOLoop.instance().stop() 
    #IOLoop.instance().stop() 

這是視圖..

import app.basic 
import tornado.web 
import time 
import os 
import shlex 

from tornado.ioloop import IOLoop 
from tornado.gen import coroutine 

#from datetime import datetime 
from lib import subprocess_helper 
from lib import ad_sizesdb, sitesdb, audit_notesdb 


class Repull(app.basic.BaseHandler): 
    @tornado.web.authenticated 
    def get(self): 
    if self.get_secure_cookie("account_type") not in ['admin']: 
    self.redirect('/') 
    else: 
    slug = self.get_argument('slug','') 
    size = self.get_argument('ad_size', '') 

    ad_sizes = ad_sizesdb.get_ad_sizes() 
    slugs = sitesdb.get_all_slugs() 
    self.render('admin_tools/repull.html', active_section='repull_invocation', ad_sizes=ad_sizes, slug=slug, slugs=slugs, size=size, expand_tools=True) 

    @tornado.web.authenticated 
    @coroutine 
    def post(self): 
    slug = self.get_argument('slug','') 
    size = self.get_argument('ad_size', '') 
    if slug != '' and size != '': 
     seconds_to_wait = 300 
     deadline = time.time() + seconds_to_wait 
     IOLoop.instance().add_timeout(deadline, subprocess_helper.on_timeout) 

     file_path = os.path.join(os.path.dirname(os.path.abspath(__file__)).replace('app', 'scripts/pull_invocation_codes.py')) 
     #cmd = shlex.split('python {0} "{1}" "adtech" "{2}"'.format(file_path, slug, size)) 
     cmd = 'ls' 
     result, error = yield subprocess_helper.call_subprocess(cmd, stdin_async=True) 

     if result != '': 
     msg = 'invocation code for {0}_{1} pulled'.format(slug, size) 
     #log_audit_note(msg) 
     self.api_response(msg) 
     else: 
     msg = 'invocation for {0}_{1} not pull something happened'.format(slug, size) 
     #log_audit_note(msg) 
     self.api_response(msg) 
    else: 
     self.error(400, 'slug or ad size blank') 
    #self.redirect('/admin/admin_tools/repull??ad_size={0}&slug={1}'.format(size, slug)) 

模板

{% set active_section = 'admin_tools' %} 
{% extends ../admin.html %} 

{% block middle_content %} 
    <div class="col-sm-6"> 
    <form name="form" action="/admin/admin_tools/repull" method="post"> 
     <div class="form-group"> 
     <label>Ad Size</label> 
     <select id="ad_size" name="ad_size" data-init-plugin="select2" style="width:100%;"> 
      <option value=""></option> 
      {% for size in ad_sizes %} 
      <option value='{{size['size']}}' {% if size['size'] == size %} selected {% end %}>{{size['size']}}</option> 
      {% end %} 
     </select> 
     </div> 
     <div class="form-group"> 
     <label>Slugs</label> 
     <select id="slug" name="slug" data-init-plugin="select2" style="width:100%;"> 
      <option value=""></option> 
      {% for s in slugs %} 
      <option value='{{s['slug']}}' {% if s['slug'] == slug %} selected {% end %}>{{s['slug']}}</option> 
      {% end %} 
     </select> 
     </div> 
     <button type="submit" id="submit" class="btn btn-primary">Pull Adtech Invocation Code</button> 
    </form> 
    </div> 
    <div class="col-sm-6"> 
    <div>Notes:</div> 
    <div id="notes"></div> 
    </div> 
{% end %} 

{% block javascript %} 
    <script> 
    $(document).ready(function() { 
    $("form").submit(function(){ 
     $('#notes').html('Running for invocation for ' + slug + '_' + adsize); 
     $.post($(this).attr("action"), $(this).serialize(), function(data) { 
     $('#notes').html(data['data']); 
     return false; 
     }); 
     return false; 
    }); 
    }); 
    </script> 
{% end %} 

那麼一點點的背景。我之所以需要這個調用是異步的,是因爲post請求觸發了另一個使用selenium來幫助自動化的文件。有些事情我並不真正瞭解並希望得到幫助,包括使用IOLoop.instance().stop()上面的鏈接使用它來幫助解決超時問題,並在稍後調用解決方法。我評論說,因爲如果我不在龍捲風線程在帖子結尾處終止。考慮到我打電話給我的方法的名稱,我認爲這是有道理的......總體而言,我希望能夠運行後異步並在完成後得到某種響應,以便可以在模板上觸發一些視覺王這樣用戶就會有某種線索發生/完成/失敗。我做錯了什麼?我該如何解決它?如果這不是最好的方法是什麼?先謝謝了。
更新:我添加了模板,想到它後,我想我想要的是在模板上正確呈現的響應。我添加了一個我正確得到的圖像,這不是我除了之外。該消息呈現在空白頁面上,但是如果您查看一下html模板,那麼當我收到響應數據時,我想要將jquery注入到div中。我在jQuery的enter image description here

+0

代碼看起來體面的給我;你究竟期待什麼,發生了什麼?你絕對不想在任何地方使用'IOLoop.stop()';這是爲了關閉整個服務器,並且在常規請求中沒有地方。你的意思可能是在POST中啓動子進程,向客戶端發送響應,然後在稍後的請求中獲取子進程的結果? –

+0

@BenDarnell在閱讀您的評論後,我對該帖子進行了一些更新。添加一些澄清,當子進程產生的結果我想發送/寫一個api響應回來..它的工作原理,除了當我發送的數據它返回一個空白頁面與JSON響應。我想讓jQuery接收響應並將響應注入到div中。 – reticentroot

+0

謝謝,我明白你現在在找什麼。不幸的是我不知道足夠的javascript/jquery來幫助你。服務器端很好;這是關於如何從JavaScript發出請求的問題。 –

回答

0

返回false,因爲我是做多後,我不得不防止默認

$("form").submit(function(e){ 
     e.preventDefault(); 
     var slug = $('#slug').val(); 
     var adsize = $('#ad_size').val(); 
     if((slug && adsize) != ''){ 
     $('#notes').html('Running for invocation for ' + slug + '_' + adsize + ' if you don\'t want to wait for the reponse you can check the audit notes later'); 
     $.post($(this).attr("action"), $(this).serialize(), function(data) { 
      $('#notes').html(data['data']); 
      return false; 
     }); 
     } 
    });