我正在嘗試使用龍捲風的異步功能。到目前爲止,我只獲得了一點成功。我正在使用我發現的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的
代碼看起來體面的給我;你究竟期待什麼,發生了什麼?你絕對不想在任何地方使用'IOLoop.stop()';這是爲了關閉整個服務器,並且在常規請求中沒有地方。你的意思可能是在POST中啓動子進程,向客戶端發送響應,然後在稍後的請求中獲取子進程的結果? –
@BenDarnell在閱讀您的評論後,我對該帖子進行了一些更新。添加一些澄清,當子進程產生的結果我想發送/寫一個api響應回來..它的工作原理,除了當我發送的數據它返回一個空白頁面與JSON響應。我想讓jQuery接收響應並將響應注入到div中。 – reticentroot
謝謝,我明白你現在在找什麼。不幸的是我不知道足夠的javascript/jquery來幫助你。服務器端很好;這是關於如何從JavaScript發出請求的問題。 –