Merge lp:~cmiller/desktopcouch/reconnect-on-couch-death into lp:desktopcouch

Proposed by Chad Miller
Status: Merged
Approved by: Rodrigo Moya
Approved revision: 168
Merged at revision: 169
Proposed branch: lp:~cmiller/desktopcouch/reconnect-on-couch-death
Merge into: lp:desktopcouch
Diff against target: 93 lines (+39/-9)
2 files modified
desktopcouch/records/server.py (+11/-3)
desktopcouch/records/server_base.py (+28/-6)
To merge this branch: bzr merge lp:~cmiller/desktopcouch/reconnect-on-couch-death
Reviewer Review Type Date Requested Status
Rodrigo Moya (community) Approve
Tim Cole (community) Approve
Review via email: mp+30710@code.launchpad.net

Commit message

On couchdb failure, reconnect with logic that starts up the couchdb server again and uses the new port.

To post a comment you must log in.
Revision history for this message
Tim Cole (tcole) :
review: Approve
Revision history for this message
Rodrigo Moya (rodrigo-moya) :
review: Approve
169. By Chad Miller

Instead of giving python-couchdb view objects to the user, give an object we own that implements reconnecting to the server on errors, and proxies commands otherwise.

170. By Chad Miller

Fixes LP: Bug#522538.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'desktopcouch/records/server.py'
2--- desktopcouch/records/server.py 2010-02-26 22:23:42 +0000
3+++ desktopcouch/records/server.py 2010-08-23 22:54:43 +0000
4@@ -49,9 +49,17 @@
5 def __init__(self, database, uri=None, record_factory=None, create=False,
6 server_class=OAuthCapableServer, oauth_tokens=None,
7 ctx=desktopcouch.local_files.DEFAULT_CONTEXT):
8- if not uri:
9- port = desktopcouch.find_port(ctx=ctx)
10- uri = "http://localhost:%s" % port
11+ self.ctx = ctx
12+ self.server_uri = uri
13 super(CouchDatabase, self).__init__(
14 database, uri, record_factory=record_factory, create=create,
15 server_class=server_class, oauth_tokens=oauth_tokens, ctx=ctx)
16+
17+ def _reconnect(self):
18+ if not self.server_uri:
19+ port = desktopcouch.find_port(ctx=self.ctx)
20+ uri = "http://localhost:%s" % port
21+ else:
22+ uri = self.server_uri
23+ super(CouchDatabase, self)._reconnect(uri=uri)
24+
25
26=== modified file 'desktopcouch/records/server_base.py'
27--- desktopcouch/records/server_base.py 2010-07-02 15:32:25 +0000
28+++ desktopcouch/records/server_base.py 2010-08-23 22:54:43 +0000
29@@ -22,7 +22,7 @@
30 """The Desktop Couch Records API."""
31
32 import httplib2, urlparse, cgi, copy
33-from time import time
34+from time import time, sleep
35 import socket
36
37 # please keep desktopcouch python 2.5 compatible for now
38@@ -170,15 +170,16 @@
39 continue
40 elif isinstance(e, socket.error):
41 logging.warn("Other socket error %s. Reconnecting.", e)
42- time.sleep(0.3)
43+ sleep(0.3)
44 self._reconnect()
45 continue
46 else:
47 raise
48
49- def _reconnect(self):
50+ def _reconnect(self, uri=None):
51 logging.info("Connecting to %s." % (self.server_uri or "discovered local port",))
52- self._server = self._server_class(self.server_uri,
53+
54+ self._server = self._server_class(uri or self.server_uri,
55 **self._server_class_extras)
56 if self._database_name not in self._server:
57 if self._create:
58@@ -432,12 +433,33 @@
59 def execute_view(self, view_name, design_doc=DEFAULT_DESIGN_DOCUMENT,
60 **params):
61 """Execute view and return results."""
62+
63+ class ReconnectingViewWrapper:
64+ """A view from python-couchdb is an object with attributes that
65+ cause HTTP requests to be fired off when accessed. If we wish
66+ to be able to reconnect on disappearance of the server, then
67+ we must intercept calls from user to python-couchdb."""
68+
69+ def __init__(wrapper, view, *args, **kwargs):
70+ wrapper.view = self.with_reconnects(view, *args, **kwargs)
71+
72+ def ___call__(wrapper, **options):
73+ return self.with_reconnects(wrapper.view.__call__, **options)
74+
75+ def __iter__(wrapper):
76+ return self.with_reconnects(wrapper.view.__iter__)
77+
78+ def __getitem__(wrapper, key):
79+ return self.with_reconnects(wrapper.view.__getitem__, key)
80+
81 if design_doc is None:
82 design_doc = view_name
83
84 view_id_fmt = "_design/%(design_doc)s/_view/%(view_name)s"
85- return self.with_reconnects(self.db.view, view_id_fmt % locals(),
86- **params)
87+ wrapper = ReconnectingViewWrapper(self.db.view,
88+ view_id_fmt % locals(),
89+ **params)
90+ return wrapper
91
92 def add_view(self, view_name, map_js, reduce_js,
93 design_doc=DEFAULT_DESIGN_DOCUMENT):

Subscribers

People subscribed via source and target branches