Skip to content

Commit a984417

Browse files
stsewdagjohnson
authored andcommitted
Refactor tasks into decorators (#4666)
* Refactor SyncRepositoryTask to decorator * Refactor UpdateDocsTask to decorator * Ignore some checks on pylint Pylint doesn't like bounded tasks * Fix lint
1 parent 61165ba commit a984417

File tree

11 files changed

+54
-83
lines changed

11 files changed

+54
-83
lines changed

readthedocs/core/management/commands/pull.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,4 @@ def handle(self, *args, **options):
2020
if args:
2121
for slug in args:
2222
version = utils.version_from_slug(slug, LATEST)
23-
tasks.SyncRepositoryTask().run(
24-
version.pk,
25-
)
23+
tasks.sync_repository_task(version.pk)

readthedocs/core/management/commands/update_api.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,5 @@ def handle(self, *args, **options):
3333
project_data = api.project(slug).get()
3434
p = APIProject(**project_data)
3535
log.info("Building %s", p)
36-
update_docs = tasks.UpdateDocsTask()
37-
update_docs.run(pk=p.pk, docker=docker)
36+
# pylint: disable=no-value-for-parameter
37+
tasks.update_docs_task(p.pk, docker=docker)

readthedocs/core/management/commands/update_repos.py

+9-6
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,9 @@ def handle(self, *args, **options):
7373
state='triggered',
7474
)
7575

76-
tasks.UpdateDocsTask().run(
77-
pk=version.project_id,
76+
# pylint: disable=no-value-for-parameter
77+
tasks.update_docs_task(
78+
version.project_id,
7879
build_pk=build.pk,
7980
version_pk=version.pk,
8081
)
@@ -89,15 +90,17 @@ def handle(self, *args, **options):
8990
active=True,
9091
uploaded=False,
9192
):
92-
tasks.UpdateDocsTask().run(
93-
pk=version.project_id,
93+
# pylint: disable=no-value-for-parameter
94+
tasks.update_docs_task(
95+
version.project_id,
9496
force=force,
9597
version_pk=version.pk,
9698
)
9799
else:
98100
log.info('Updating all docs')
99101
for project in Project.objects.all():
100-
tasks.UpdateDocsTask().run(
101-
pk=project.pk,
102+
# pylint: disable=no-value-for-parameter
103+
tasks.update_docs_task(
104+
project.pk,
102105
force=force,
103106
)

readthedocs/core/management/commands/update_versions.py

+7-4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from django.core.management.base import BaseCommand
55

66
from readthedocs.builds.models import Version
7-
from readthedocs.projects.tasks import UpdateDocsTask
7+
from readthedocs.projects.tasks import update_docs_task
88

99

1010
class Command(BaseCommand):
@@ -13,6 +13,9 @@ class Command(BaseCommand):
1313

1414
def handle(self, *args, **options):
1515
for version in Version.objects.filter(active=True, built=False):
16-
update_docs = UpdateDocsTask()
17-
update_docs.run(version.project_id, record=False,
18-
version_pk=version.pk)
16+
# pylint: disable=no-value-for-parameter
17+
update_docs_task(
18+
version.project_id,
19+
record=False,
20+
version_pk=version.pk
21+
)

readthedocs/core/utils/__init__.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,10 @@ def prepare_build(
8989
:param record: whether or not record the build in a new Build object
9090
:param force: build the HTML documentation even if the files haven't changed
9191
:param immutable: whether or not create an immutable Celery signature
92-
:returns: Celery signature of UpdateDocsTask to be executed
92+
:returns: Celery signature of update_docs_task to be executed
9393
"""
9494
# Avoid circular import
95-
from readthedocs.projects.tasks import UpdateDocsTask
95+
from readthedocs.projects.tasks import update_docs_task
9696
from readthedocs.builds.models import Build
9797

9898
if project.skip:
@@ -138,9 +138,8 @@ def prepare_build(
138138
options['soft_time_limit'] = time_limit
139139
options['time_limit'] = int(time_limit * 1.2)
140140

141-
update_docs_task = UpdateDocsTask()
142141
return update_docs_task.signature(
143-
(project.pk,),
142+
args=(project.pk,),
144143
kwargs=kwargs,
145144
options=options,
146145
immutable=True,

readthedocs/core/views/hooks.py

+3-6
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from readthedocs.builds.constants import LATEST
1313
from readthedocs.projects import constants
1414
from readthedocs.projects.models import Project, Feature
15-
from readthedocs.projects.tasks import SyncRepositoryTask
15+
from readthedocs.projects.tasks import sync_repository_task
1616

1717
import logging
1818

@@ -128,12 +128,9 @@ def _build_url(url, projects, branches):
128128
for project in projects:
129129
(built, not_building) = build_branches(project, branches)
130130
if not built:
131-
# Call SyncRepositoryTask to update tag/branch info
131+
# Call sync_repository_task to update tag/branch info
132132
version = project.versions.get(slug=LATEST)
133-
sync_repository = SyncRepositoryTask()
134-
sync_repository.apply_async(
135-
args=(version.pk,),
136-
)
133+
sync_repository_task.delay(version.pk)
137134
msg = '(URL Build) Syncing versions for %s' % project.slug
138135
log.info(msg)
139136
all_built[project.slug] = built

readthedocs/projects/apps.py

-7
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,3 @@
55

66
class ProjectsConfig(AppConfig):
77
name = 'readthedocs.projects'
8-
9-
def ready(self):
10-
from readthedocs.projects import tasks
11-
from readthedocs.worker import app
12-
13-
app.tasks.register(tasks.SyncRepositoryTask)
14-
app.tasks.register(tasks.UpdateDocsTask)

readthedocs/projects/tasks.py

+8-24
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121

2222
import requests
2323
from builtins import str
24-
from celery import Task
2524
from celery.exceptions import SoftTimeLimitExceeded
2625
from django.conf import settings
2726
from django.core.urlresolvers import reverse
@@ -173,19 +172,11 @@ def validate_duplicate_reserved_versions(self, data):
173172
)
174173

175174

176-
# TODO SyncRepositoryTask should be refactored into a standard celery task,
177-
# there is no more need to have this be a separate class
178-
class SyncRepositoryTask(Task):
179-
175+
@app.task(max_retries=5, default_retry_delay=7 * 60)
176+
def sync_repository_task(version_pk):
180177
"""Celery task to trigger VCS version sync."""
181-
182-
max_retries = 5
183-
default_retry_delay = (7 * 60)
184-
name = __name__ + '.sync_repository'
185-
186-
def run(self, *args, **kwargs):
187-
step = SyncRepositoryTaskStep()
188-
return step.run(*args, **kwargs)
178+
step = SyncRepositoryTaskStep()
179+
return step.run(version_pk)
189180

190181

191182
class SyncRepositoryTaskStep(SyncRepositoryMixin):
@@ -226,17 +217,10 @@ def run(self, version_pk): # pylint: disable=arguments-differ
226217
return False
227218

228219

229-
# TODO UpdateDocsTask should be refactored into a standard celery task,
230-
# there is no more need to have this be a separate class
231-
class UpdateDocsTask(Task):
232-
233-
max_retries = 5
234-
default_retry_delay = (7 * 60)
235-
name = __name__ + '.update_docs'
236-
237-
def run(self, *args, **kwargs):
238-
step = UpdateDocsTaskStep(task=self)
239-
return step.run(*args, **kwargs)
220+
@app.task(bind=True, max_retries=5, default_retry_delay=7 * 60)
221+
def update_docs_task(self, project_id, *args, **kwargs):
222+
step = UpdateDocsTaskStep(task=self)
223+
return step.run(project_id, *args, **kwargs)
240224

241225

242226
class UpdateDocsTaskStep(SyncRepositoryMixin):

readthedocs/rtd_tests/tests/test_celery.py

+4-10
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,7 @@ def test_update_docs(self):
7676
build = get(Build, project=self.project,
7777
version=self.project.versions.first())
7878
with mock_api(self.repo) as mapi:
79-
update_docs = tasks.UpdateDocsTask()
80-
result = update_docs.delay(
79+
result = tasks.update_docs_task.delay(
8180
self.project.pk,
8281
build_pk=build.pk,
8382
record=False,
@@ -94,8 +93,7 @@ def test_update_docs_unexpected_setup_exception(self, mock_setup_vcs):
9493
build = get(Build, project=self.project,
9594
version=self.project.versions.first())
9695
with mock_api(self.repo) as mapi:
97-
update_docs = tasks.UpdateDocsTask()
98-
result = update_docs.delay(
96+
result = tasks.update_docs_task.delay(
9997
self.project.pk,
10098
build_pk=build.pk,
10199
record=False,
@@ -112,8 +110,7 @@ def test_update_docs_unexpected_build_exception(self, mock_build_docs):
112110
build = get(Build, project=self.project,
113111
version=self.project.versions.first())
114112
with mock_api(self.repo) as mapi:
115-
update_docs = tasks.UpdateDocsTask()
116-
result = update_docs.delay(
113+
result = tasks.update_docs_task.delay(
117114
self.project.pk,
118115
build_pk=build.pk,
119116
record=False,
@@ -123,10 +120,7 @@ def test_update_docs_unexpected_build_exception(self, mock_build_docs):
123120
def test_sync_repository(self):
124121
version = self.project.versions.get(slug=LATEST)
125122
with mock_api(self.repo):
126-
sync_repository = tasks.SyncRepositoryTask()
127-
result = sync_repository.apply_async(
128-
args=(version.pk,),
129-
)
123+
result = tasks.sync_repository_task.delay(version.pk)
130124
self.assertTrue(result.successful())
131125

132126
@patch('readthedocs.projects.tasks.api_v2')

readthedocs/rtd_tests/tests/test_core_utils.py

+16-16
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def setUp(self):
1818
self.project = get(Project, container_time_limit=None)
1919
self.version = get(Version, project=self.project)
2020

21-
@mock.patch('readthedocs.projects.tasks.UpdateDocsTask')
21+
@mock.patch('readthedocs.projects.tasks.update_docs_task')
2222
def test_trigger_custom_queue(self, update_docs):
2323
"""Use a custom queue when routing the task"""
2424
self.project.build_queue = 'build03'
@@ -34,17 +34,17 @@ def test_trigger_custom_queue(self, update_docs):
3434
'time_limit': 720,
3535
'soft_time_limit': 600,
3636
}
37-
update_docs().signature.assert_has_calls([
37+
update_docs.signature.assert_has_calls([
3838
mock.call(
39-
(self.project.pk,),
39+
args=(self.project.pk,),
4040
kwargs=kwargs,
4141
options=options,
4242
immutable=True,
4343
),
4444
])
45-
update_docs().signature().apply_async.assert_called()
45+
update_docs.signature().apply_async.assert_called()
4646

47-
@mock.patch('readthedocs.projects.tasks.UpdateDocsTask')
47+
@mock.patch('readthedocs.projects.tasks.update_docs_task')
4848
def test_trigger_build_time_limit(self, update_docs):
4949
"""Pass of time limit"""
5050
trigger_build(project=self.project, version=self.version)
@@ -59,17 +59,17 @@ def test_trigger_build_time_limit(self, update_docs):
5959
'time_limit': 720,
6060
'soft_time_limit': 600,
6161
}
62-
update_docs().signature.assert_has_calls([
62+
update_docs.signature.assert_has_calls([
6363
mock.call(
64-
(self.project.pk,),
64+
args=(self.project.pk,),
6565
kwargs=kwargs,
6666
options=options,
6767
immutable=True,
6868
),
6969
])
70-
update_docs().signature().apply_async.assert_called()
70+
update_docs.signature().apply_async.assert_called()
7171

72-
@mock.patch('readthedocs.projects.tasks.UpdateDocsTask')
72+
@mock.patch('readthedocs.projects.tasks.update_docs_task')
7373
def test_trigger_build_invalid_time_limit(self, update_docs):
7474
"""Time limit as string"""
7575
self.project.container_time_limit = '200s'
@@ -85,17 +85,17 @@ def test_trigger_build_invalid_time_limit(self, update_docs):
8585
'time_limit': 720,
8686
'soft_time_limit': 600,
8787
}
88-
update_docs().signature.assert_has_calls([
88+
update_docs.signature.assert_has_calls([
8989
mock.call(
90-
(self.project.pk,),
90+
args=(self.project.pk,),
9191
kwargs=kwargs,
9292
options=options,
9393
immutable=True,
9494
),
9595
])
96-
update_docs().signature().apply_async.assert_called()
96+
update_docs.signature().apply_async.assert_called()
9797

98-
@mock.patch('readthedocs.projects.tasks.UpdateDocsTask')
98+
@mock.patch('readthedocs.projects.tasks.update_docs_task')
9999
def test_trigger_build_rounded_time_limit(self, update_docs):
100100
"""Time limit should round down"""
101101
self.project.container_time_limit = 3
@@ -111,15 +111,15 @@ def test_trigger_build_rounded_time_limit(self, update_docs):
111111
'time_limit': 3,
112112
'soft_time_limit': 3,
113113
}
114-
update_docs().signature.assert_has_calls([
114+
update_docs.signature.assert_has_calls([
115115
mock.call(
116-
(self.project.pk,),
116+
args=(self.project.pk,),
117117
kwargs=kwargs,
118118
options=options,
119119
immutable=True,
120120
),
121121
])
122-
update_docs().signature().apply_async.assert_called()
122+
update_docs.signature().apply_async.assert_called()
123123

124124
def test_slugify(self):
125125
"""Test additional slugify"""

readthedocs/rtd_tests/tests/test_privacy.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def setUp(self):
2727
self.tester.set_password('test')
2828
self.tester.save()
2929

30-
tasks.UpdateDocsTask.delay = mock.Mock()
30+
tasks.update_docs_task.delay = mock.Mock()
3131

3232
def _create_kong(self, privacy_level='private',
3333
version_privacy_level='private'):

0 commit comments

Comments
 (0)