Check if any jobs exist before querying jobs

At the moment the dashboard does two API calls to find out if a service
has:

1. Scheduled jobs
2. Normal jobs

API calls are slow because they are synchronous, go over the network and
touch the database. We can’t cache these API calls because:
- a scheduled job could become a normal job at any time
- the statistics on a normal job are constantly updating

However there are plenty of services which don’t have any jobs, and
probably never will. And finding out if a service has any jobs is
reliably cacheable (because as soon as a service creates its first job
it has some jobs).

So this commit:
- refactors the way we get scheduled/normal jobs into the job_api_client
  to make the view a bit slimmer
- makes an additional, Redis-wrapped call to find out if any jobs exist
  before trying to get the jobs

This should result in a speedup on the dashboard, and can be used in the
future if there’s anywhere else we want to show or hide something
depending on whether a service has created any jobs (I have some ideas).
This commit is contained in:
Chris Hill-Scott
2018-07-20 10:18:51 +01:00
parent c1b2f63671
commit 505de52d38
5 changed files with 122 additions and 27 deletions

View File

@@ -1,6 +1,8 @@
import uuid
from unittest.mock import ANY
import pytest
from app.notify_client.job_api_client import JobApiClient
@@ -8,6 +10,7 @@ def test_client_creates_job_data_correctly(mocker, fake_uuid):
job_id = fake_uuid
service_id = fake_uuid
mocker.patch('app.notify_client.current_user', id='1')
mock_redis_set = mocker.patch('app.notify_client.RedisClient.set')
expected_data = {
"id": job_id,
@@ -24,6 +27,11 @@ def test_client_creates_job_data_correctly(mocker, fake_uuid):
client.create_job(service_id, job_id)
mock_post.assert_called_once_with(url=expected_url, data=expected_data)
mock_redis_set.assert_called_once_with(
'has_jobs-{}'.format(service_id),
True,
ex=604800,
)
def test_client_schedules_job(mocker, fake_uuid):
@@ -300,3 +308,59 @@ def test_cancel_job(mocker):
url='/service/{}/job/{}/cancel'.format('service_id', 'job_id'),
data={}
)
@pytest.mark.parametrize('job_data, expected_cache_value', [
(
[{'data': [1, 2, 3], 'statistics': []}],
'true',
),
(
[],
'false',
),
])
def test_has_jobs_sets_cache(
mocker,
fake_uuid,
job_data,
expected_cache_value,
):
mock_get = mocker.patch(
'app.notify_client.job_api_client.JobApiClient.get',
return_value={'data': job_data}
)
mock_redis_set = mocker.patch('app.notify_client.RedisClient.set')
JobApiClient().has_jobs(fake_uuid)
mock_get.assert_called_once_with(
url='/service/{}/job'.format(fake_uuid),
params={'page': 1}
)
mock_redis_set.assert_called_once_with(
'has_jobs-{}'.format(fake_uuid),
expected_cache_value,
ex=604800,
)
@pytest.mark.parametrize('cache_value, return_value', [
(b'true', True),
(b'false', False),
])
def test_has_jobs_returns_from_cache(
mocker,
fake_uuid,
cache_value,
return_value,
):
mock_redis_get = mocker.patch(
'app.notify_client.RedisClient.get',
return_value=cache_value,
)
assert JobApiClient().has_jobs(fake_uuid) is return_value
mock_redis_get.assert_called_once_with(
'has_jobs-{}'.format(fake_uuid)
)