4

tornado(およびサードパーティのtornadowsモジュール)を使用してSOAPWebサービスを実装しています。私のサービスの操作の1つは別の操作を呼び出す必要があるので、チェーンがあります。

  1. 操作Aへの(SOAPUIを介した)外部要求
  2. 操作Bへの(要求モジュールを介した)内部要求
  3. 操作Bからの内部応答
  4. 操作Aからの外部応答

すべてが1つのサービスで実行されているため、どこかでブロックされています。私はトルネードの非同期機能に精通していません。

すべてが単一のURLで受信され、SOAPActionリクエストヘッダー値に基づいて特定の操作(処理を実行するメソッド)が呼び出されるため、リクエスト処理メソッド(post)は1つだけです。postメソッドを@tornado.web.asynchronousで装飾し、最後にself.finish()を呼び出しましたが、サイコロはありません。

竜巻はこのシナリオを処理できますか?もしそうなら、どのように実装できますか?

編集(追加されたコード):

class SoapHandler(tornado.web.RequestHandler):
    @tornado.web.asynchronous
    def post(self):
        """ Method post() to process of requests and responses SOAP messages """
        try:
            self._request = self._parseSoap(self.request.body)
            soapaction = self.request.headers['SOAPAction'].replace('"','')
            self.set_header('Content-Type','text/xml')
            for operations in dir(self):
                operation = getattr(self,operations)
                method = ''
                if callable(operation) and hasattr(operation,'_is_operation'):
                    num_methods = self._countOperations()
                    if hasattr(operation,'_operation') and soapaction.endswith(getattr(operation,'_operation')) and num_methods > 1:
                        method = getattr(operation,'_operation')
                        self._response = self._executeOperation(operation,method=method)
                        break
                    elif num_methods == 1:
                        self._response = self._executeOperation(operation,method='')
                        break
            soapmsg = self._response.getSoap().toprettyxml()
            self.write(soapmsg)
            self.finish()
        except Exception as detail:
            #traceback.print_exc(file=sys.stdout)
            wsdl_nameservice = self.request.uri.replace('/','').replace('?wsdl','').replace('?WSDL','')
            fault = soapfault('Error in web service : {fault}'.format(fault=detail), wsdl_nameservice)
            self.write(fault.getSoap().toxml())
            self.finish()

これは、リクエストハンドラーからのpostメソッドです。これは私が使用しているWebサービスモジュールからのものです(コードではありません)が、非同期デコレーターとself.finish()を追加しました。基本的には、正しい操作を呼び出すだけです(要求のSOAPActionで指定されています)。

class CountryService(soaphandler.SoapHandler):
    @webservice(_params=GetCurrencyRequest, _returns=GetCurrencyResponse)
    def get_currency(self, input):
        result = db_query(input.country, 'currency')
        get_currency_response = GetCurrencyResponse()
        get_currency_response.currency = result
        headers = None
        return headers, get_currency_response

    @webservice(_params=GetTempRequest, _returns=GetTempResponse)
    def get_temp(self, input):
        get_temp_response = GetTempResponse()
        curr = self.make_curr_request(input.country)
        get_temp_response.temp = curr
        headers = None
        return headers, get_temp_response

    def make_curr_request(self, country):

        soap_request = """<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/' xmlns:coun='CountryService'>
   <soapenv:Header/>
   <soapenv:Body>
      <coun:GetCurrencyRequestget_currency>
         <country>{0}</country>
      </coun:GetCurrencyRequestget_currency>
   </soapenv:Body>
</soapenv:Envelope>""".format(country)

        headers = {'Content-Type': 'text/xml;charset=UTF-8', 'SOAPAction': '"http://localhost:8080/CountryService/get_currency"'}
        r = requests.post('http://localhost:8080/CountryService', data=soap_request, headers=headers)
        try:
            tree = etree.fromstring(r.content)
            currency = tree.xpath('//currency')
            message = currency[0].text
        except:
            message = "Failure"
        return message

これらは、Webサービスの2つの操作(get_currencyとget_temp)です。したがって、SOAPUIはget_tempにヒットし、get_currencyへのSOAPリクエストを作成します(make_curr_requestおよびrequestsモジュールを介して)。次に、結果をチェーンバックしてSOAPUIに送り返す必要があります。

サービスの実際の操作は意味がありません(温度を求められたときに通貨を返す)が、私は機能を動作させようとしているだけであり、これらは私が持っている操作です。

4

2 に答える 2

7

あなたの石鹸モジュールやリクエストは非同期ではないと思います。

@asyncronous デコレータを追加することは、戦いの半分に過ぎないと思います。現在、関数内で非同期リクエストを行っていません (すべてのリクエストがブロックされているため、メソッドが終了するまでサーバーが拘束されます)。

tornados AsynHttpClientを使用して、これを切り替えることができます。これは、リクエストの正確な代替としてほとんど使用できます。ドキュメントの例から:

class MainHandler(tornado.web.RequestHandler):
    @tornado.web.asynchronous
    def get(self):
        http = tornado.httpclient.AsyncHTTPClient()
        http.fetch("http://friendfeed-api.com/v2/feed/bret",
                   callback=self.on_response)

    def on_response(self, response):
        if response.error: raise tornado.web.HTTPError(500)
        json = tornado.escape.json_decode(response.body)
        self.write("Fetched " + str(len(json["entries"])) + " entries "
                   "from the FriendFeed API")
        self.finish()

彼らのメソッドは非同期で装飾されており、非同期の http リクエストを作成しています。ここで流れが少し変になります。AsyncHttpClient を使用すると、イベント ループがロックされません (今週トルネードを使い始めたばかりです。私の用語がまだすべて正しくない場合は、気をつけてください)。これにより、サーバーは着信要求を自由に処理できます。asynchttp リクエストが終了すると、コールバック メソッドが実行されます。この場合はon_response.

ここでは、リクエストを tornado asynchttp クライアントに簡単に置き換えることができます。ただし、ソープ サービスの場合は、さらに複雑になる可能性があります。SOAP クライアントの周りにローカル Web サービスを作成し、tornado async http クライアントを使用して非同期要求を作成できますか???

これにより、デコレータを使用して修正できる複雑なコールバック ロジックが作成されます。gen

于 2013-02-01T17:31:43.180 に答える
0

この問題は昨日から修正されています。

プルリクエスト: https://github.com/rancavil/tornado-webservices/pull/23

例: ここでは、引数を取らず、バージョンを返す単純な Web サービスを示します。次のことを行う必要があることに注意してください。

  • メソッド宣言: メソッドをデコレート@gen.coroutine
  • 結果を返す: 使用raise gen.Return(data)

コード:

from tornado import gen
from tornadows.soaphandler import SoapHandler
...

class Example(SoapHandler):
    @gen.coroutine
    @webservice(_params=None, _returns=Version)
    def Version(self):
        _version = Version()
        # async stuff here, let's suppose you ask other rest service or resource for the version details.
        # ...
        # returns the result.
        raise gen.Return(_version)

乾杯!

于 2014-12-29T21:56:28.043 に答える