Skip to content

Commit 0fd9fa3

Browse files
committed
Ignore 404s on close/destroy requests due to possible retry
1 parent d3a64a1 commit 0fd9fa3

3 files changed

Lines changed: 89 additions & 9 deletions

File tree

morango/sync/operations.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1390,9 +1390,8 @@ def close_transfer_session(self, context):
13901390
Closes remote transfer session
13911391
13921392
:type context: NetworkSessionContext
1393-
:return: The Response
13941393
"""
1395-
return context.connection._close_transfer_session(context.transfer_session)
1394+
context.connection._close_transfer_session(context.transfer_session)
13961395

13971396
def put_buffers(self, context, buffers):
13981397
"""
@@ -1763,8 +1762,5 @@ def handle(self, context):
17631762
"""
17641763
:type context: NetworkSessionContext
17651764
"""
1766-
response = self.close_transfer_session(context)
1767-
remote_status = transfer_statuses.COMPLETED
1768-
if response.status_code < 200 or response.status_code >= 300:
1769-
remote_status = transfer_statuses.ERRORED
1770-
return remote_status
1765+
self.close_transfer_session(context)
1766+
return transfer_statuses.COMPLETED

morango/sync/syncsession.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import os
77
import socket
88
import uuid
9+
from functools import wraps
910
from io import BytesIO
1011
from urllib.parse import urljoin
1112
from urllib.parse import urlparse
@@ -53,6 +54,7 @@
5354

5455
DBBackend = load_backend(connection)
5556

57+
5658
def _join_with_logical_operator(lst, operator):
5759
op = ") {operator} (".format(operator=operator)
5860
return "(({items}))".format(items=op.join(lst))
@@ -77,6 +79,25 @@ def _get_client_ip_for_server(server_host, server_port):
7779
return IP
7880

7981

82+
def ignore_404(target):
83+
"""
84+
Decorator that wraps callables to ignore 404s caused by its use of requests
85+
:param target: A callable
86+
:return: A callable
87+
"""
88+
@wraps(target)
89+
def wrapper(*args, **kwargs):
90+
try:
91+
return target(*args, **kwargs)
92+
except HTTPError as e:
93+
if e.response is None or e.response.status_code != 404:
94+
raise e
95+
else:
96+
logger.debug(f"Ignoring 404 raised by {target.__name__}")
97+
98+
return wrapper
99+
100+
80101
# borrowed from https://github.com/django/django/blob/1.11.20/django/utils/text.py#L295
81102
def compress_string(s, compresslevel=9):
82103
zbuf = BytesIO()
@@ -479,13 +500,15 @@ def _update_transfer_session(self, data, transfer_session):
479500
json=data,
480501
)
481502

503+
@ignore_404
482504
def _close_transfer_session(self, transfer_session):
483-
return self.session.delete(
505+
self.session.delete(
484506
self.urlresolve(api_urls.TRANSFERSESSION, lookup=transfer_session.id)
485507
)
486508

509+
@ignore_404
487510
def _close_sync_session(self, sync_session):
488-
return self.session.delete(
511+
self.session.delete(
489512
self.urlresolve(api_urls.SYNCSESSION, lookup=sync_session.id)
490513
)
491514

tests/testapp/tests/sync/test_syncsession.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from morango.models.certificates import Key
2222
from morango.models.certificates import ScopeDefinition
2323
from morango.models.core import SyncSession
24+
from morango.models.core import TransferSession
2425
from morango.models.fields.crypto import SharedKey
2526
from morango.sync.context import LocalSessionContext
2627
from morango.sync.context import NetworkSessionContext
@@ -236,6 +237,66 @@ def create(**data):
236237
self.network_connection.close_sync_session(client.sync_session)
237238
self.assertEqual(SyncSession.objects.filter(active=True).count(), 0)
238239

240+
def test_close_transfer_session_ignores_404(self):
241+
mock_response = mock.Mock()
242+
mock_response.status_code = 404
243+
transfer_session = mock.Mock(spec=TransferSession)
244+
transfer_session.id = uuid.uuid4().hex
245+
246+
with mock.patch.object(
247+
self.network_connection.session,
248+
"delete",
249+
side_effect=HTTPError(response=mock_response),
250+
):
251+
# should not raise even though the server returned 404
252+
self.network_connection._close_transfer_session(transfer_session)
253+
254+
def test_close_sync_session_ignores_404(self):
255+
mock_response = mock.Mock()
256+
mock_response.status_code = 404
257+
sync_session = mock.Mock(spec=SyncSession)
258+
sync_session.id = uuid.uuid4().hex
259+
260+
with mock.patch.object(
261+
self.network_connection.session,
262+
"delete",
263+
side_effect=HTTPError(response=mock_response),
264+
):
265+
# should not raise even though the server returned 404
266+
self.network_connection._close_sync_session(sync_session)
267+
268+
def test_close_sync_session_raises_500(self):
269+
mock_response = mock.Mock()
270+
mock_response.status_code = 500
271+
sync_session = mock.Mock(spec=SyncSession)
272+
sync_session.id = uuid.uuid4().hex
273+
274+
e = HTTPError(response=mock_response)
275+
276+
with mock.patch.object(
277+
self.network_connection.session,
278+
"delete",
279+
side_effect=e,
280+
):
281+
with self.assertRaises(type(e)) as raised:
282+
self.network_connection._close_sync_session(sync_session)
283+
self.assertEqual(e, raised.exception)
284+
285+
def test_close_sync_session_raises_no_response(self):
286+
sync_session = mock.Mock(spec=SyncSession)
287+
sync_session.id = uuid.uuid4().hex
288+
289+
e = HTTPError()
290+
291+
with mock.patch.object(
292+
self.network_connection.session,
293+
"delete",
294+
side_effect=e,
295+
):
296+
with self.assertRaises(type(e)) as raised:
297+
self.network_connection._close_sync_session(sync_session)
298+
self.assertEqual(e, raised.exception)
299+
239300
@mock.patch.object(SyncSession.objects, "create")
240301
def test_resume_sync_session(self, mock_create):
241302
def create(**data):

0 commit comments

Comments
 (0)