title: Nested web service calls with tornado (async?)
body: <p>I am implementing a SOAP web service using tornado (and the third party tornadows module). One of the operations in my service needs to call another so I have the chain:</p>
  
  <ol>
  <li>External request in (via SOAPUI) to operation A</li>
  <li>Internal request (via requests module) in to operation B</li>
  <li>Internal response from operation B</li>
  <li>External response from operation A</li>
  </ol>
  
  <p>Because it is all running in one service it is being blocked somewhere though. I'm not familiar with tornado's async functionality. </p>
  
  <p>There is only one request handling method (post) because everything comes in on the single url and then the specific operation (method doing processing) is called based on the SOAPAction request header value. I have decorated my post method with @tornado.web.asynchronous and called self.finish() at the end but no dice.</p>
  
  <p>Can tornado handle this scenario and if so how can I implement it?</p>
  
  <p>EDIT (added code):</p>
  
  <pre><code>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 &gt; 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()
  </code></pre>
  
  <p>This is the post method from the request handler. It's from the web services module I'm using (so not my code) but I added the async decorator and self.finish(). All it basically does is call the correct operation (as dictated in the SOAPAction of the request). </p>
  
  <pre><code>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 = """&lt;soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/' xmlns:coun='CountryService'&gt;
     &lt;soapenv:Header/&gt;
     &lt;soapenv:Body&gt;
        &lt;coun:GetCurrencyRequestget_currency&gt;
           &lt;country&gt;{0}&lt;/country&gt;
        &lt;/coun:GetCurrencyRequestget_currency&gt;
     &lt;/soapenv:Body&gt;
  &lt;/soapenv:Envelope&gt;""".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
  </code></pre>
  
  <p>These are two of the operations of the web service (get_currency &amp; get_temp). So SOAPUI hits get_temp, which makes a SOAP request to get_currency (via make_curr_request and the requests module). Then the results should just chain back and be sent back to SOAPUI. </p>
  
  <p>The actual operation of the service makes no sense (returning the currency when asked for the temperature) but i'm just trying to get the functionality working and these are the operations I have. </p>