Merge lp:~rockstar/launchpad/job-suspended-status into lp:launchpad

Proposed by Paul Hummer
Status: Merged
Approved by: Muharem Hrnjadovic
Approved revision: not available
Merged at revision: not available
Proposed branch: lp:~rockstar/launchpad/job-suspended-status
Merge into: lp:launchpad
Diff against target: 129 lines (+76/-1)
3 files modified
lib/lp/services/job/interfaces/job.py (+16/-0)
lib/lp/services/job/model/job.py (+14/-1)
lib/lp/services/job/tests/test_job.py (+46/-0)
To merge this branch: bzr merge lp:~rockstar/launchpad/job-suspended-status
Reviewer Review Type Date Requested Status
Muharem Hrnjadovic (community) code Approve
Review via email: mp+17173@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Paul Hummer (rockstar) wrote :

This branch adds a JobStatus.SUSPENDED state, as well as suspend and resume
methods for IJob interfaces. Jobs can only be suspended if they are in a
waiting state, and suspended jobs can only transition to waiting.

Revision history for this message
Muharem Hrnjadovic (al-maisan) wrote :

Looks good!

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/services/job/interfaces/job.py'
2--- lib/lp/services/job/interfaces/job.py 2010-01-04 21:15:39 +0000
3+++ lib/lp/services/job/interfaces/job.py 2010-01-11 22:52:17 +0000
4@@ -56,6 +56,12 @@
5 The job was run, but failed. Will not be run again.
6 """)
7
8+ SUSPENDED = DBItem(4, """
9+ Suspended
10+
11+ The job is suspended, so should not be run.
12+ """)
13+
14
15 class IJob(Interface):
16 """Basic attributes of a job."""
17@@ -101,6 +107,16 @@
18 def queue():
19 """Mark the job as queued for processing."""
20
21+ def suspend():
22+ """Mark the job as suspended.
23+
24+ Only waiting jobs can be suspended."""
25+
26+ def resume():
27+ """Mark the job as waiting.
28+
29+ Only suspended jobs can be resumed."""
30+
31
32 class IRunnableJob(IJob):
33 """Interface for jobs that can be run via the JobRunner."""
34
35=== modified file 'lib/lp/services/job/model/job.py'
36--- lib/lp/services/job/model/job.py 2009-12-10 19:37:06 +0000
37+++ lib/lp/services/job/model/job.py 2010-01-11 22:52:17 +0000
38@@ -60,13 +60,16 @@
39 # List of the valid target states from a given state.
40 _valid_transitions = {
41 JobStatus.WAITING:
42- (JobStatus.RUNNING,),
43+ (JobStatus.RUNNING,
44+ JobStatus.SUSPENDED),
45 JobStatus.RUNNING:
46 (JobStatus.COMPLETED,
47 JobStatus.FAILED,
48 JobStatus.WAITING),
49 JobStatus.FAILED: (),
50 JobStatus.COMPLETED: (),
51+ JobStatus.SUSPENDED:
52+ (JobStatus.WAITING,),
53 }
54
55 def _set_status(self, status):
56@@ -116,6 +119,16 @@
57 self._set_status(JobStatus.WAITING)
58 self.date_finished = datetime.datetime.now(UTC)
59
60+ def suspend(self):
61+ """See `IJob`."""
62+ self._set_status(JobStatus.SUSPENDED)
63+
64+ def resume(self):
65+ """See `IJob`."""
66+ if self.status is not JobStatus.SUSPENDED:
67+ raise InvalidTransition(self._status, JobStatus.WAITING)
68+ self._set_status(JobStatus.WAITING)
69+
70
71 Job.ready_jobs = Select(
72 Job.id,
73
74=== modified file 'lib/lp/services/job/tests/test_job.py'
75--- lib/lp/services/job/tests/test_job.py 2009-12-09 20:03:31 +0000
76+++ lib/lp/services/job/tests/test_job.py 2010-01-11 22:52:17 +0000
77@@ -153,6 +153,52 @@
78 job = Job(_status=JobStatus.FAILED)
79 self.assertRaises(InvalidTransition, job.queue)
80
81+ def test_suspend(self):
82+ """A job that is in the WAITING state can be suspended."""
83+ job = Job(_status=JobStatus.WAITING)
84+ job.suspend()
85+ self.assertEqual(
86+ job.status,
87+ JobStatus.SUSPENDED)
88+
89+ def test_suspend_when_running(self):
90+ """When a job is running, attempting to suspend is invalid."""
91+ job = Job(_status=JobStatus.RUNNING)
92+ self.assertRaises(InvalidTransition, job.suspend)
93+
94+ def test_suspend_when_completed(self):
95+ """When a job is completed, attempting to suspend is invalid."""
96+ job = Job(_status=JobStatus.COMPLETED)
97+ self.assertRaises(InvalidTransition, job.suspend)
98+
99+ def test_suspend_when_failed(self):
100+ """When a job is failed, attempting to suspend is invalid."""
101+ job = Job(_status=JobStatus.FAILED)
102+ self.assertRaises(InvalidTransition, job.suspend)
103+
104+ def test_resume(self):
105+ """A job that is suspended can be resumed."""
106+ job = Job(_status=JobStatus.SUSPENDED)
107+ job.resume()
108+ self.assertEqual(
109+ job.status,
110+ JobStatus.WAITING)
111+
112+ def test_resume_when_running(self):
113+ """When a job is running, attempting to resume is invalid."""
114+ job = Job(_status=JobStatus.RUNNING)
115+ self.assertRaises(InvalidTransition, job.resume)
116+
117+ def test_resume_when_completed(self):
118+ """When a job is completed, attempting to resume is invalid."""
119+ job = Job(_status=JobStatus.COMPLETED)
120+ self.assertRaises(InvalidTransition, job.resume)
121+
122+ def test_resume_when_failed(self):
123+ """When a job is failed, attempting to resume is invalid."""
124+ job = Job(_status=JobStatus.FAILED)
125+ self.assertRaises(InvalidTransition, job.resume)
126+
127
128 class TestReadiness(TestCase):
129 """Test the implementation of readiness."""