Merge lp:~andrea.corbellini/lazr.restful/fix-375353 into lp:lazr.restful

Proposed by Andrea Corbellini
Status: Merged
Merged at revision: not available
Proposed branch: lp:~andrea.corbellini/lazr.restful/fix-375353
Merge into: lp:lazr.restful
Diff against target: None lines
To merge this branch: bzr merge lp:~andrea.corbellini/lazr.restful/fix-375353
Reviewer Review Type Date Requested Status
Francis J. Lacoste (community) Needs Resubmitting
Review via email: mp+6472@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Francis J. Lacoste (flacoste) wrote :

Hi Andrea,

First of all, let me thank you for your prompt initiative in tackling that bug and going through the paperwork to become a Canonical community contributor.

Like we discussed on IRC, it's usually a good idea to have a chat about your strategy to fix the bug with another LP developer.

The approach you took here isn't really appropriate since it would affect all methods invocation (and not only when invoked through the web service). This means that internal calls to the method would also be cached. And since this is a global cache that don't take into account parameters passed, it's really something we want to do.

So for this problem, what we really want is a webservice annotation. These are
defined in lazr.restful.declarations. The annotation should simply do error
checking on the annotation parameters and context of usage. And then stick the
caching duration in the annotation data structure.

In the BaseResourceOperationAdapter, you can then use that information to set
Cache-control header on the request response. That will leave caching to the
client which is more efficient overall (it doesn't use server resources, will
save on bandwith. Since parameters are encoded in the URL, that's also fine.)

Only GET operation should be thus cacheable. (So it should be an error to use
cache_for() in conjunction with annotation others than
export_as_read_operation.

One last item, all branches to be merged should have proper tests. In this
case, I suggest you look at src/lazr/restful/docs/webservice-declarations.txt
That's where the existing annotations are documented and tested. This should
give you a starting idea.

Don't hesitate to contact me on IRC if you need more information or encounter
any problem.

Again, thanks a lot for your initiative.

review: Needs Resubmitting

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'src/lazr/restful/methodcache.py'
2--- src/lazr/restful/methodcache.py 1970-01-01 00:00:00 +0000
3+++ src/lazr/restful/methodcache.py 2009-05-12 15:32:08 +0000
4@@ -0,0 +1,45 @@
5+# Copyright 2008 Canonical Ltd. All rights reserved.
6+
7+"""Cache the results of calls to methods."""
8+
9+__metaclass__ = type
10+__all__ = [
11+ 'cache_results'
12+ ]
13+
14+from time import time
15+from types import FunctionType
16+
17+class CachedMethod:
18+ """Helper class for ``cache_result``."""
19+
20+ def call(*args, **kwargs):
21+ now = time()
22+ last_execution = self.last_execution
23+ if (last_execution > 0) and (now - last_execution <= self.duration):
24+ return self.cached_result
25+ else:
26+ result = self.cached_result = self.method(*args, **kwargs)
27+ return result
28+
29+
30+class cache_result:
31+ """Cache the result of a function for the specified seconds."""
32+
33+ last_execution = -1
34+
35+ def __init__(self, duration):
36+ self.duration = duration
37+
38+ def __call__(self, method):
39+ self.method = method
40+
41+ call = CachedMethod().call
42+ funct = FunctionType(call.func_code,
43+ call.func_globals,
44+ call.func_name,
45+ call.func_defaults,
46+ call.func_closure)
47+
48+ funct.func_globals['self'] = self
49+ return funct

Subscribers

People subscribed via source and target branches