Advertisment

Using hooks in Google App Engine

author-image
CIOL Bureau
Updated On
New Update

BANGALORE, INDIA: As code grows in the wild, it sometimes becomes hard to maintain and modify. Implementing features like profiling datastore usage or adding "audit data" (who changed that row?) throughout the codebase can be tough. How can we be sure that we did not miss any place in our sources? How can we prevent another developer from making errors when later extending the code?

Advertisment

Background

Often, we would like to implement a change in the global behavior of an application that has nothing to do with its business logic. The goal is to make a big change with very little risk and code. We would like to apply a crosscutting concern, such as logging of performance-related data, to an entire application. We would like to achieve this goal globally, no matter what kind of higher-level api (Models versus datastore, Django versus webob) a developer uses.

The natural module to use is api_proxy_map, a low-level registry of RPC services that delegate higher level API calls to the appropriate service implementation. Traditionally, the way of modifying api_proxy_map is to monkeypatch this module, and replace its main entry point apiproxy_stub_map.MakeSyncCall. While this approach will work in some cases, it is not without its dangers. To make unit testing easier, other modules sometimes choose to inject the MakeSyncCall method and store a local reference to it -- this way, a test can easily substitute a mock instead.

Advertisment

The memcache module is a good example how this technique is used. Unfortunately, this also means that whatever memcache-Client is created before we apply our patch will bypass our modifications altogether. That could be for example the case if the memcache module was imported by a script before our patch was applied. Tracking down and fixing all these references is complex, and there is no guarantee that a new version of an SDK (or any other externally developed tool library that we might use for some other purpose) will not introduce new static dependencies later on.

Luckily, there is an alternative to monkeypatching. Version 1.1.8 of the SDK introduces a new mechanism into api_proxy_map: the concept of hooks. Any developer can now define a method with the same signature as MakeSyncCall:

def hook(service, call, request, response):

Advertisment

...

and register it with the runtime using one of the following methods:

apiproxy_stub_map.apiproxy.GetPreCallHooks().Append('unique_name', hook, 'optional_api_identifier')

apiproxy_stub_map.apiproxy.GetPostCallHooks().Append('unique_name', hook, 'optional_api_identifier')

apiproxy_stub_map.apiproxy.GetPreCallHooks().Push('unique_name', hook, 'optional_api_identifier')

apiproxy_stub_map.apiproxy.GetPostCallHooks().Push('unique_name', hook, 'optional_api_identifier')

Advertisment

There are two different types of hooks. A PreCallHook is executed before an RPC call is made, a PostCallHook is executed after the RPC call. It is also possible to specify an optional api identifier that will make sure that a hook only gets invoked for a particular type of rpc (such as datastore or memcache). It is possible to register more than one hook to the apiproxy: Append will append a new hook to the end of the list of existing hooks, Push will append the hook at the beginning.

Click here for more....!

(The above article is taken from code.google.com under Creative commons licensing)

tech-news