0

我正在 python 烧瓶中为 Jasmin SMS Gateway 编写 Web 服务,以从网关创建和删除用户。如果是 POST 请求,我将调用 runScenario() ,然后我将启动 reactor.run() ,它将在网关中创建用户。此代码在第一次 Web 服务调用时运行完美,但在第二次调用时它给了我这个错误:

raise error.ReactorNotRestartable()
ReactorNotRestartable

这是我的烧瓶应用程序:

#!/usr/bin/env python
from flask import Flask, jsonify, request, Response, make_response, abort
from JasminIntegration import *

JasminWebservice = Flask(__name__)

@JasminWebservice.errorhandler(404)
def not_found(error):
    return make_response(jsonify({'error': 'Not found'}), 404)

@JasminWebservice.route('/jsms/webservice', methods=['POST'])
def create_user():
    if not request.json or not 'username' in request.json:
        abort(400)

    runScenario(request)
    reactor.run()
    return jsonify({'response':'Success'}), 201

if __name__ == '__main__':    
    JasminWebservice.run(host="0.0.0.0",port=7034,debug=True)

我正在调用在 JasminIntegration.py 中定义的 runScenario()

#!/usr/bin/env python
import sys
import pickle
from flask import abort
from twisted.internet import defer, reactor
from jasmin.managers.proxies import SMPPClientManagerPBProxy
from jasmin.routing.proxies import RouterPBProxy
from jasmin.routing.Routes import DefaultRoute
from jasmin.routing.jasminApi import SmppClientConnector, User, Group, MtMessagingCredential, SmppsCredential
from jasmin.protocols.smpp.configs import SMPPClientConfig
from twisted.web.client import getPage


@defer.inlineCallbacks
def runScenario(Request):
    try:
        proxy_router = RouterPBProxy()
        yield proxy_router.connect('127.0.0.1', 8988, 'radmin', 'rpwd')

        if Request.method == 'POST':            
            smppUser = Request.json['username']
            smppPass = Request.json['password']
            smppThroughput = Request.json['tp']
            smppBindSessions = Request.json['sessions']

            if not smppUser:
                abort(400)

            if len(smppPass) == 0 or len(smppPass) > 8:
                abort(400)

            if not smppThroughput.isdigit():
                abort(400)

            if not smppBindSessions.isdigit():
                abort(400)

            # Provisiong router with users
            smpp_cred = SmppsCredential()
            yield smpp_cred.setQuota('max_bindings',int(smppBindSessions))

            mt_cred = MtMessagingCredential()
            yield mt_cred.setQuota('smpps_throughput' , smppThroughput)
            #yield mt_cred.setQuota('submit_sm_count' , 500)

            g1 = Group('clients')
            u1 = User(uid = smppUser, group = g1, username = smppUser, password = smppPass, mt_credential = mt_cred, smpps_credential = smpp_cred)
            yield proxy_router.group_add(g1)
            yield proxy_router.user_add(u1)

        if Request.method == 'DELETE':

            smppUser = Request.json['username']

            if not smppUser:
                abort(404)

            yield proxy_router.user_remove(smppUser) 
    except Exception, e:
        yield "%s" %str(e)

    finally:
        print "Stopping Reactor"
        reactor.stop()

请帮我解决这个问题:

4

3 回答 3

1

在 Twisted 中,Reactor 在设计上是不可重启的,它执行不容易重启的初始化和终结。

在提供的示例中,您使用的是开发 WSGI 服务器(flask 的默认服务器,http://werkzeug.pocoo.org/docs/0.11/serving/),默认情况下它似乎是单线程的。

如果您避免使用线程并改用多进程服务器,您的问题就会消失。即,如果您像这样运行它会起作用(请参阅processes=2 => 每个请求将在一个新进程中处理,但不超过 2 个并发的):

if __name__ == '__main__':                                                      
    JasminWebservice.run(host="0.0.0.0", port=7034, debug=True, processes=2)

我不会依赖这一点——在编写单元测试和限制你的应用程序仅在多进程环境中运行时你会遇到类似的麻烦,这不是一个好方法。

但看起来问题出在你的应用程序设计上——你为什么需要 Flask 和一个额外的 WSGI 服务器?您可以完全以扭曲的方式构建 REST API,最终只运行一个反应器,该反应器将处理对您的 API 的查询和传入的请求。

于 2016-08-19T19:12:02.227 回答
0

您无法停止反应器并再次运行它。你得到的错误是设计使然。考虑使用klein它使用werkzeuglikeflask和leveragestwisted来建立网络。语法甚至相似。将您的代码翻译成klein如下所示:

import json
from klein import Klein
from exception werkzeug.exceptions import NotFound
from JasminIntegration import *

JasminWebservice = Klein()

@JasminWebservice.handle_errors(NotFound)
def not_found(request, error):
    request.setResponseCode(404)
    return json.dumps({'error': 'Not found'})

@JasminWebservice.route('/jsms/webservice', methods=['POST'])
def create_user(request):
    try:
        data = json.loads(request.content.read())
        if not data or if 'username' not in data:
            raise NotFound()
    except:     # yeah I know this isn't best practice
        raise NotFound()

    runScenario(request)
    request.setResponseCode(201)
    return json.dumps({'response':'Success'})

if __name__ == '__main__':    
    JasminWebservice.run("0.0.0.0", port=7034)

作为旁注,reactor除非您想完全退出应用程序,否则不应停止。

于 2016-08-20T00:51:29.740 回答
0

@feast我也尝试过扭曲但遇到了同样的问题,因为反应堆不可重新启动。在扭曲中我做了这样的事情:

#!/usr/bin/env python
from pprint import pprint
import json
from twisted.web import server, resource
from twisted.internet import reactor
from JasminIntegration import *
import ast

class Simple(resource.Resource):
    isLeaf = True
    def render_GET(self, request):
        return "<html>Hello, world!</html>"

    def render_POST(self, request):
        pprint(request.__dict__)
        newdata = request.content.getvalue()
        newdata = ast.literal_eval(newdata)
        ret = runScenario(newdata)
        #print  request.content
        #print newdata
        return ''
site = server.Site(Simple())
reactor.listenTCP(7034, site)
reactor.run()
于 2016-08-22T06:38:12.633 回答