[CalendarServer-changes] [15572] CalendarServer/trunk/twistedcaldav
source_changes at macosforge.org
source_changes at macosforge.org
Tue May 3 09:46:29 PDT 2016
Revision: 15572
http://trac.calendarserver.org//changeset/15572
Author: cdaboo at apple.com
Date: 2016-05-03 09:46:28 -0700 (Tue, 03 May 2016)
Log Message:
-----------
Add some more exception handlers to turn cross-pod errors into 503's.
Modified Paths:
--------------
CalendarServer/trunk/twistedcaldav/resource.py
CalendarServer/trunk/twistedcaldav/storebridge.py
CalendarServer/trunk/twistedcaldav/test/test_resource.py
Modified: CalendarServer/trunk/twistedcaldav/resource.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/resource.py 2016-05-03 13:48:29 UTC (rev 15571)
+++ CalendarServer/trunk/twistedcaldav/resource.py 2016-05-03 16:46:28 UTC (rev 15572)
@@ -58,6 +58,7 @@
from txdav.caldav.datastore.util import normalizationLookup
from txdav.common.icommondatastore import InternalDataStoreError, \
SyncTokenValidException, ExternalShareFailed
+from txdav.common.datastore.podding.base import FailedCrossPodRequestError
from txdav.xml import element
from txdav.xml.element import dav_namespace
@@ -363,6 +364,12 @@
# the transaction commit
self._transactionError = False
response = StatusResponse(responsecode.SERVICE_UNAVAILABLE, "Shared collection not valid - removing.")
+ except FailedCrossPodRequestError:
+ # This happens when a cross-pod connection attempt fails. Treat as a 503 so the client
+ # can try again once the pod is back up.
+ response = StatusResponse(responsecode.SERVICE_UNAVAILABLE, "Unable to do cross-pod request.")
+ response.headers.setHeader("Retry-After", time.time() + config.TransactionHTTPRetrySeconds)
+
if transaction is None:
transaction = self._associatedTransaction
if transaction is not None:
Modified: CalendarServer/trunk/twistedcaldav/storebridge.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/storebridge.py 2016-05-03 13:48:29 UTC (rev 15571)
+++ CalendarServer/trunk/twistedcaldav/storebridge.py 2016-05-03 16:46:28 UTC (rev 15572)
@@ -260,7 +260,9 @@
@param arg: description of error or C{None}
@type arg: C{str} or C{None}
"""
- raise HTTPError(StatusResponse(responsecode.SERVICE_UNAVAILABLE, arg if arg is not None else str(err)))
+ response = StatusResponse(responsecode.SERVICE_UNAVAILABLE, arg if arg is not None else str(err))
+ response.headers.setHeader("Retry-After", time.time() + config.TransactionHTTPRetrySeconds)
+ raise HTTPError(response)
@classmethod
@@ -398,7 +400,11 @@
"""
if self._newStoreObject:
- newStoreObject = yield self._newStoreObject.objectResourceWithName(name)
+ try:
+ newStoreObject = yield self._newStoreObject.objectResourceWithName(name)
+ except Exception as err:
+ self._handleStoreException(err, self.StoreExceptionsErrors)
+ raise
similar = self._childClass(
newStoreObject,
Modified: CalendarServer/trunk/twistedcaldav/test/test_resource.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_resource.py 2016-05-03 13:48:29 UTC (rev 15571)
+++ CalendarServer/trunk/twistedcaldav/test/test_resource.py 2016-05-03 16:46:28 UTC (rev 15572)
@@ -28,6 +28,9 @@
from twistedcaldav.test.util import \
InMemoryPropertyStore, StoreTestCase, SimpleStoreRequest
+from txdav.caldav.datastore.sql import Calendar
+from txdav.common.datastore.podding.base import FailedCrossPodRequestError
+from txdav.common.icommondatastore import ExternalShareFailed
from txdav.xml import element
from txdav.xml.element import HRef
@@ -90,11 +93,11 @@
-class TransactionTimeoutTests(StoreTestCase):
+class TransactionErrorTests(StoreTestCase):
@inlineCallbacks
def setUp(self):
- yield super(TransactionTimeoutTests, self).setUp()
+ yield super(TransactionErrorTests, self).setUp()
@inlineCallbacks
@@ -130,7 +133,77 @@
self.fail("HTTPError not raised")
+ @inlineCallbacks
+ def test_conduitRetry(self):
+ """
+ Test that a cross-pod error during an HTTP request results in a 503 error
+ with a Retry-After header.
+ """
+ # Patch request handling to raise an exception
+ def _iCalendarRolledup(self, request):
+ raise FailedCrossPodRequestError()
+ self.patch(CalendarCollectionResource, "iCalendarRolledup", _iCalendarRolledup)
+
+ self.patch(self.store, "timeoutTransactions", 1)
+
+ # Run delayed request
+ authPrincipal = yield self.actualRoot.findPrincipalForAuthID("user01")
+ request = SimpleStoreRequest(self, "GET", "/calendars/__uids__/user01/calendar/", authPrincipal=authPrincipal)
+ response = yield self.send(request)
+ self.assertEqual(response.code, responsecode.SERVICE_UNAVAILABLE)
+ self.assertTrue(response.headers.hasHeader("Retry-After"))
+ self.assertApproximates(int(response.headers.getRawHeaders("Retry-After")[0]), config.TransactionHTTPRetrySeconds, 1)
+
+
+ @inlineCallbacks
+ def test_failedShareRetry(self):
+ """
+ Test that a cross-pod error during an HTTP request results in a 503 error
+ without a Retry-After header.
+ """
+
+ # Patch request handling to raise an exception
+ def _iCalendarRolledup(self, request):
+ raise ExternalShareFailed()
+ self.patch(CalendarCollectionResource, "iCalendarRolledup", _iCalendarRolledup)
+
+ # Run delayed request
+ authPrincipal = yield self.actualRoot.findPrincipalForAuthID("user01")
+ request = SimpleStoreRequest(self, "GET", "/calendars/__uids__/user01/calendar/", authPrincipal=authPrincipal)
+ response = yield self.send(request)
+ self.assertEqual(response.code, responsecode.SERVICE_UNAVAILABLE)
+ self.assertFalse(response.headers.hasHeader("Retry-After"))
+
+
+ @inlineCallbacks
+ def test_failedPodChildRetry(self):
+ """
+ Test that a cross-pod error during an HTTP request results in a 503 error
+ with a Retry-After header.
+ """
+
+ # Patch request handling to raise an exception
+ def _objectResourceWithName(self, name):
+ raise FailedCrossPodRequestError()
+ self.patch(Calendar, "objectResourceWithName", _objectResourceWithName)
+
+ self.patch(self.store, "timeoutTransactions", 1)
+
+ # Run delayed request
+ authPrincipal = yield self.actualRoot.findPrincipalForAuthID("user01")
+ request = SimpleStoreRequest(self, "GET", "/calendars/__uids__/user01/calendar/1.ics", authPrincipal=authPrincipal)
+ try:
+ yield self.send(request)
+ except HTTPError as e:
+ self.assertEqual(e.response.code, responsecode.SERVICE_UNAVAILABLE)
+ self.assertTrue(e.response.headers.hasHeader("Retry-After"))
+ self.assertApproximates(int(e.response.headers.getRawHeaders("Retry-After")[0]), config.TransactionHTTPRetrySeconds, 1)
+ else:
+ self.fail("HTTPError not raised")
+
+
+
class CommonHomeResourceTests(TestCase):
def test_commonHomeliveProperties(self):
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20160503/00561657/attachment-0001.html>
More information about the calendarserver-changes
mailing list