Hooks

This example is an enhanced version of the HelloWorld example that uses service 'hooks' to apply cross-cutting behavior to the service. In this example, the service hooks are used to gather performance information on both the method execution as well as the duration of the entire call, including serialization and deserialization. The available hooks are:

  • onCall

This is the first thing called in the service

  • onWsdl

Called before the wsdl is requested

  • onWsdlException

Called after an exception was thrown when generating the wsdl (shouldn't happen very much)

  • onMethodExec

Called right before the service method is executed

  • onResults

Called right after the service method is executed

  • onException

Called after an exception occurred in either the service method or in serialization

  • onReturn

This is the very last thing called before the wsgi app exits

These method can be used to easily apply cross-cutting functionality accross all methods in the service to do things like database transaction management, logging and measuring performance. This example also employs the threadlocal request (soaplib.wsgi_soap.request) object to hold the data points for this request.

from soaplib.wsgi_soap import SimpleWSGISoapApp
from soaplib.service import soapmethod
from soaplib.serializers.primitive import String, Integer, Array

from soaplib.wsgi_soap import request
from time import time

class HelloWorldService(SimpleWSGISoapApp):
    
    @soapmethod(String,Integer,_returns=Array(String))
    def say_hello(self,name,times):
        results = []
        for i in range(0,times):
            results.append('Hello, %s'%name)
        return results
    
    def onCall(self,environ):
        request.additional['call_start'] = time()

    def onMethodExec(self,environ,body,py_params,soap_params):
        request.additional['method_start'] = time()

    def onResults(self,environ,py_results,soap_results):
        request.additional['method_end'] = time()

    def onReturn(self,environ,returnString):
        call_start = request.additional['call_start']
        call_end = time()
        method_start = request.additional['method_start']
        method_end = request.additional['method_end']
        
        print 'Method took [%s] - total execution time[%s]'%(method_end-method_start,call_end-call_start)
        

def make_client():
    from soaplib.client import make_service_client
    client = make_service_client('http://localhost:7889/',HelloWorldService())
    return client
    
if __name__=='__main__':
    from cherrypy._cpwsgiserver import CherryPyWSGIServer
    server = CherryPyWSGIServer(('localhost',7889),HelloWorldService())
    server.start()

Running this produces:

Method took [0.000195980072021] - total execution time[0.00652194023132]
Method took [0.000250101089478] - total execution time[0.00567507743835]
Method took [0.000144004821777] - total execution time[0.00521206855774]
Method took [0.000141859054565] - total execution time[0.00512409210205]
Method took [0.00377607345581] - total execution time[0.00511980056763]
Method took [0.00118803977966] - total execution time[0.00673604011536]
Method took [0.000146150588989] - total execution time[0.00157499313354]
Method took [0.0231170654297] - total execution time[0.0245010852814]
Method took [0.000166893005371] - total execution time[0.01802110672]

These may be helpful in finding bottlenecks in process, but this technique can also be used to commit/rollback transactions or do setup/teardown operations for all methods in a service