我试图掌握使用龙卷风的异步功能。到目前为止,我只取得了一定的成功。我使用我发现的here的修改版本来协助我的异步..也许这不是最好的方式,你告诉我你的想法或者是否有更好的方法。这是我用来帮助处理异步请求的subprocess_helper.py文件。
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
答案 0 :(得分:0)
由于我发了多个帖子,我不得不阻止默认
$("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;
});
}
});