Skip to content
Snippets Groups Projects
Commit bc600269 authored by Sybren A. Stüvel's avatar Sybren A. Stüvel
Browse files

Server: use different HTTP headers to do conditional fetch of depsgraph

We need a format that can handle sub-second precision, which is not
provided by the HTTP date format (RFC 1123). This means that we can't use
the Last-Modified header, as it may be incorrectly interpreted and
rewritten by HaProxy, Apache or other software in the path between client
& server.
parent bde4d6dd
No related branches found
No related tags found
No related merge requests found
...@@ -225,8 +225,8 @@ def tasks_cancel_requested(manager_id): ...@@ -225,8 +225,8 @@ def tasks_cancel_requested(manager_id):
def get_depsgraph(manager_id, request_json): def get_depsgraph(manager_id, request_json):
"""Returns the dependency graph of all tasks assigned to the given Manager. """Returns the dependency graph of all tasks assigned to the given Manager.
Use the HTTP header If-Modified-Since to limit the dependency graph to tasks Use the HTTP header X-Flamenco-If-Updated-Since to limit the dependency
that have been modified since that timestamp. graph to tasks that have been modified since that timestamp.
""" """
import dateutil.parser import dateutil.parser
...@@ -234,7 +234,7 @@ def get_depsgraph(manager_id, request_json): ...@@ -234,7 +234,7 @@ def get_depsgraph(manager_id, request_json):
from flamenco import current_flamenco from flamenco import current_flamenco
from flamenco.utils import report_duration from flamenco.utils import report_duration
modified_since = request.headers.get('If-Modified-Since') modified_since = request.headers.get('X-Flamenco-If-Updated-Since')
with report_duration(log, 'depsgraph query'): with report_duration(log, 'depsgraph query'):
tasks_coll = current_flamenco.db('tasks') tasks_coll = current_flamenco.db('tasks')
...@@ -297,9 +297,12 @@ def get_depsgraph(manager_id, request_json): ...@@ -297,9 +297,12 @@ def get_depsgraph(manager_id, request_json):
if depsgraph: if depsgraph:
last_modification = max(task['_updated'] for task in depsgraph) last_modification = max(task['_updated'] for task in depsgraph)
log.debug('Last modification was %s', last_modification) log.debug('Last modification was %s', last_modification)
# We need a format that can handle sub-second precision. # We need a format that can handle sub-second precision, which is not provided by the
resp.headers['Last-Modified'] = last_modification.isoformat() # HTTP date format (RFC 1123). This means that we can't use the Last-Modified header, as
resp.headers['X-Last-Modified-Format'] = 'ISO-8601' # it may be incorrectly interpreted and rewritten by HaProxy, Apache or other software
# in the path between client & server.
resp.headers['X-Flamenco-Last-Updated'] = last_modification.isoformat()
resp.headers['X-Flamenco-Last-Updated-Format'] = 'ISO-8601'
return resp return resp
......
...@@ -91,8 +91,8 @@ class DepsgraphTest(AbstractFlamencoTest): ...@@ -91,8 +91,8 @@ class DepsgraphTest(AbstractFlamencoTest):
depstask1 = next(t for t in depsgraph if t['_id'] == unicode(task1['_id'])) depstask1 = next(t for t in depsgraph if t['_id'] == unicode(task1['_id']))
self.assertEqual(set(task1.keys()), set(depstask1.keys())) self.assertEqual(set(task1.keys()), set(depstask1.keys()))
# The 'Last-Modified' header should contain the last-changed task. # The 'X-Flamenco-Last-Updated' header should contain the last-changed task.
last_modified = parse(resp.headers['Last-Modified']) last_modified = parse(resp.headers['X-Flamenco-Last-Updated'])
with self.app.test_request_context(): with self.app.test_request_context():
task0 = self.flamenco.db('tasks').find_one({'_id': self.task_ids[0]}) task0 = self.flamenco.db('tasks').find_one({'_id': self.task_ids[0]})
self.assertEqual(task0['_updated'], last_modified) self.assertEqual(task0['_updated'], last_modified)
...@@ -132,12 +132,12 @@ class DepsgraphTest(AbstractFlamencoTest): ...@@ -132,12 +132,12 @@ class DepsgraphTest(AbstractFlamencoTest):
# Get a clean slate first, so that we get the timestamp of last modification # Get a clean slate first, so that we get the timestamp of last modification
resp = self.get('/api/flamenco/managers/%s/depsgraph' % self.mngr_id, resp = self.get('/api/flamenco/managers/%s/depsgraph' % self.mngr_id,
auth_token=self.mngr_token) auth_token=self.mngr_token)
last_modified = resp.headers['Last-Modified'] last_modified = resp.headers['X-Flamenco-Last-Updated']
# Do the subsequent call, it should return nothing. # Do the subsequent call, it should return nothing.
self.get('/api/flamenco/managers/%s/depsgraph' % self.mngr_id, self.get('/api/flamenco/managers/%s/depsgraph' % self.mngr_id,
auth_token=self.mngr_token, auth_token=self.mngr_token,
headers={'If-Modified-Since': last_modified}, headers={'X-Flamenco-If-Updated-Since': last_modified},
expected_status=304) expected_status=304)
# Change some tasks to see what we get back. # Change some tasks to see what we get back.
...@@ -148,7 +148,7 @@ class DepsgraphTest(AbstractFlamencoTest): ...@@ -148,7 +148,7 @@ class DepsgraphTest(AbstractFlamencoTest):
resp = self.get('/api/flamenco/managers/%s/depsgraph' % self.mngr_id, resp = self.get('/api/flamenco/managers/%s/depsgraph' % self.mngr_id,
auth_token=self.mngr_token, auth_token=self.mngr_token,
headers={'If-Modified-Since': last_modified}) headers={'X-Flamenco-If-Updated-Since': last_modified})
depsgraph = resp.json()['depsgraph'] depsgraph = resp.json()['depsgraph']
self.assertEqual(2, len(depsgraph)) # we should not get the cancel-requested task back. self.assertEqual(2, len(depsgraph)) # we should not get the cancel-requested task back.
...@@ -158,8 +158,8 @@ class DepsgraphTest(AbstractFlamencoTest): ...@@ -158,8 +158,8 @@ class DepsgraphTest(AbstractFlamencoTest):
unicode(self.task_ids[2])}, unicode(self.task_ids[2])},
deps_tids) deps_tids)
# The 'Last-Modified' header should contain the last-changed task. # The 'X-Flamenco-Last-Updated' header should contain the last-changed task.
last_modified = parse(resp.headers['Last-Modified']) last_modified = parse(resp.headers['X-Flamenco-Last-Updated'])
with self.app.test_request_context(): with self.app.test_request_context():
task0 = self.flamenco.db('tasks').find_one({'_id': self.task_ids[0]}) task0 = self.flamenco.db('tasks').find_one({'_id': self.task_ids[0]})
task2 = self.flamenco.db('tasks').find_one({'_id': self.task_ids[2]}) task2 = self.flamenco.db('tasks').find_one({'_id': self.task_ids[2]})
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment