launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #20330
[Merge] lp:~cjwatson/launchpad/job-default-timeout into lp:launchpad
Colin Watson has proposed merging lp:~cjwatson/launchpad/job-default-timeout into lp:launchpad.
Commit message:
Set a default timeout function when running jobs.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Related bugs:
Bug #1578961 in Launchpad itself: "Newly pushed git branches are not shown in launchpad web"
https://bugs.launchpad.net/launchpad/+bug/1578961
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/job-default-timeout/+merge/293990
Set a default timeout function when running jobs.
This makes GitHostingClient usable from jobs again following the conversion to urlfetch.
--
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/launchpad/job-default-timeout into lp:launchpad.
=== modified file 'lib/lp/code/model/tests/test_githosting.py'
--- lib/lp/code/model/tests/test_githosting.py 2016-05-03 18:42:18 +0000
+++ lib/lp/code/model/tests/test_githosting.py 2016-05-06 09:37:15 +0000
@@ -20,6 +20,7 @@
)
from testtools.matchers import MatchesStructure
from zope.component import getUtility
+from zope.interface import implementer
from zope.security.proxy import removeSecurityProxy
from lp.code.errors import (
@@ -28,14 +29,27 @@
GitRepositoryScanFault,
)
from lp.code.interfaces.githosting import IGitHostingClient
+from lp.services.job.interfaces.job import (
+ IRunnableJob,
+ JobStatus,
+ )
+from lp.services.job.model.job import Job
+from lp.services.job.runner import (
+ BaseRunnableJob,
+ JobRunner,
+ )
+from lp.services.timeout import (
+ get_default_timeout_function,
+ set_default_timeout_function,
+ )
from lp.services.webapp.url import urlappend
from lp.testing import TestCase
-from lp.testing.layers import LaunchpadZopelessLayer
+from lp.testing.layers import ZopelessDatabaseLayer
class TestGitHostingClient(TestCase):
- layer = LaunchpadZopelessLayer
+ layer = ZopelessDatabaseLayer
def setUp(self):
super(TestGitHostingClient, self).setUp()
@@ -44,7 +58,8 @@
self.request = None
@contextmanager
- def mockRequests(self, status_code=200, content=b""):
+ def mockRequests(self, status_code=200, content=b"",
+ set_default_timeout=True):
@all_requests
def handler(url, request):
self.assertIsNone(self.request)
@@ -52,7 +67,13 @@
return {"status_code": status_code, "content": content}
with HTTMock(handler):
- yield
+ original_timeout_function = get_default_timeout_function()
+ if set_default_timeout:
+ set_default_timeout_function(lambda: 60.0)
+ try:
+ yield
+ finally:
+ set_default_timeout_function(original_timeout_function)
def assertRequest(self, url_suffix, json_data=None, **kwargs):
self.assertThat(self.request, MatchesStructure.byEquality(
@@ -249,3 +270,24 @@
"Failed to get file from Git repository: Unexpected size"
" (256 vs 0)",
self.client.getBlob, "123", "dir/path/file/name")
+
+ def test_works_in_job(self):
+ # `GitHostingClient` is usable from a running job.
+ @implementer(IRunnableJob)
+ class GetRefsJob(BaseRunnableJob):
+ def __init__(self, testcase):
+ super(GetRefsJob, self).__init__()
+ self.job = Job()
+ self.testcase = testcase
+
+ def run(self):
+ with self.testcase.mockRequests(
+ content=b'{"refs/heads/master": {}}',
+ set_default_timeout=False):
+ self.refs = self.testcase.client.getRefs("123")
+
+ job = GetRefsJob(self)
+ JobRunner([job]).runAll()
+ self.assertEqual(JobStatus.COMPLETED, job.job.status)
+ self.assertEqual({"refs/heads/master": {}}, job.refs)
+ self.assertRequest("repo/123/refs", method="GET")
=== modified file 'lib/lp/services/job/runner.py'
--- lib/lp/services/job/runner.py 2015-08-04 00:19:36 +0000
+++ lib/lp/services/job/runner.py 2016-05-06 09:37:15 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2012 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Facilities for running Jobs."""
@@ -75,6 +75,10 @@
MailController,
set_immediate_mail_delivery,
)
+from lp.services.timeout import (
+ get_default_timeout_function,
+ set_default_timeout_function,
+ )
from lp.services.twistedsupport import run_reactor
from lp.services.webapp import errorlog
@@ -299,7 +303,13 @@
return True
def runJob(self, job, fallback):
- super(BaseJobRunner, self).runJob(IRunnableJob(job), fallback)
+ original_timeout_function = get_default_timeout_function()
+ if job.lease_expires is not None:
+ set_default_timeout_function(lambda: job.getTimeout())
+ try:
+ super(BaseJobRunner, self).runJob(IRunnableJob(job), fallback)
+ finally:
+ set_default_timeout_function(original_timeout_function)
def userErrorTypes(self, job):
return removeSecurityProxy(job).user_error_types
=== modified file 'lib/lp/services/job/tests/test_runner.py'
--- lib/lp/services/job/tests/test_runner.py 2015-07-28 00:28:51 +0000
+++ lib/lp/services/job/tests/test_runner.py 2016-05-06 09:37:15 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2016 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Tests for job-running facilities."""
@@ -42,6 +42,10 @@
TwistedJobRunner,
)
from lp.services.log.logger import BufferLogger
+from lp.services.timeout import (
+ get_default_timeout_function,
+ set_default_timeout_function,
+ )
from lp.services.webapp import errorlog
from lp.testing import (
TestCaseWithFactory,
@@ -360,6 +364,26 @@
self.assertNotIn(job, runner.completed_jobs)
self.assertIn(job, runner.incomplete_jobs)
+ def test_runJob_sets_default_timeout_function(self):
+ """runJob sets a default timeout function for urlfetch."""
+ class RecordDefaultTimeoutJob(NullJob):
+ def __init__(self):
+ super(RecordDefaultTimeoutJob, self).__init__("")
+
+ def run(self):
+ self.default_timeout = get_default_timeout_function()()
+
+ original_timeout_function = get_default_timeout_function()
+ set_default_timeout_function(None)
+ try:
+ job = RecordDefaultTimeoutJob()
+ job.job.acquireLease()
+ JobRunner([job]).runJob(job, None)
+ self.assertEqual(JobStatus.COMPLETED, job.job.status)
+ self.assertThat(job.default_timeout, GreaterThan(0))
+ finally:
+ set_default_timeout_function(original_timeout_function)
+
def test_runJobHandleErrors_oops_generated_notify_fails(self):
"""A second oops is logged if the notification of the oops fails."""
job = RaisingJobRaisingNotifyOops('boom')
Follow ups