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
=== modified file 'lib/lp/services/job/interfaces/job.py'
--- lib/lp/services/job/interfaces/job.py 2010-01-04 21:15:39 +0000
+++ lib/lp/services/job/interfaces/job.py 2010-01-11 22:52:17 +0000
@@ -56,6 +56,12 @@
56 The job was run, but failed. Will not be run again.56 The job was run, but failed. Will not be run again.
57 """)57 """)
5858
59 SUSPENDED = DBItem(4, """
60 Suspended
61
62 The job is suspended, so should not be run.
63 """)
64
5965
60class IJob(Interface):66class IJob(Interface):
61 """Basic attributes of a job."""67 """Basic attributes of a job."""
@@ -101,6 +107,16 @@
101 def queue():107 def queue():
102 """Mark the job as queued for processing."""108 """Mark the job as queued for processing."""
103109
110 def suspend():
111 """Mark the job as suspended.
112
113 Only waiting jobs can be suspended."""
114
115 def resume():
116 """Mark the job as waiting.
117
118 Only suspended jobs can be resumed."""
119
104120
105class IRunnableJob(IJob):121class IRunnableJob(IJob):
106 """Interface for jobs that can be run via the JobRunner."""122 """Interface for jobs that can be run via the JobRunner."""
107123
=== modified file 'lib/lp/services/job/model/job.py'
--- lib/lp/services/job/model/job.py 2009-12-10 19:37:06 +0000
+++ lib/lp/services/job/model/job.py 2010-01-11 22:52:17 +0000
@@ -60,13 +60,16 @@
60 # List of the valid target states from a given state.60 # List of the valid target states from a given state.
61 _valid_transitions = {61 _valid_transitions = {
62 JobStatus.WAITING:62 JobStatus.WAITING:
63 (JobStatus.RUNNING,),63 (JobStatus.RUNNING,
64 JobStatus.SUSPENDED),
64 JobStatus.RUNNING:65 JobStatus.RUNNING:
65 (JobStatus.COMPLETED,66 (JobStatus.COMPLETED,
66 JobStatus.FAILED,67 JobStatus.FAILED,
67 JobStatus.WAITING),68 JobStatus.WAITING),
68 JobStatus.FAILED: (),69 JobStatus.FAILED: (),
69 JobStatus.COMPLETED: (),70 JobStatus.COMPLETED: (),
71 JobStatus.SUSPENDED:
72 (JobStatus.WAITING,),
70 }73 }
7174
72 def _set_status(self, status):75 def _set_status(self, status):
@@ -116,6 +119,16 @@
116 self._set_status(JobStatus.WAITING)119 self._set_status(JobStatus.WAITING)
117 self.date_finished = datetime.datetime.now(UTC)120 self.date_finished = datetime.datetime.now(UTC)
118121
122 def suspend(self):
123 """See `IJob`."""
124 self._set_status(JobStatus.SUSPENDED)
125
126 def resume(self):
127 """See `IJob`."""
128 if self.status is not JobStatus.SUSPENDED:
129 raise InvalidTransition(self._status, JobStatus.WAITING)
130 self._set_status(JobStatus.WAITING)
131
119132
120Job.ready_jobs = Select(133Job.ready_jobs = Select(
121 Job.id,134 Job.id,
122135
=== modified file 'lib/lp/services/job/tests/test_job.py'
--- lib/lp/services/job/tests/test_job.py 2009-12-09 20:03:31 +0000
+++ lib/lp/services/job/tests/test_job.py 2010-01-11 22:52:17 +0000
@@ -153,6 +153,52 @@
153 job = Job(_status=JobStatus.FAILED)153 job = Job(_status=JobStatus.FAILED)
154 self.assertRaises(InvalidTransition, job.queue)154 self.assertRaises(InvalidTransition, job.queue)
155155
156 def test_suspend(self):
157 """A job that is in the WAITING state can be suspended."""
158 job = Job(_status=JobStatus.WAITING)
159 job.suspend()
160 self.assertEqual(
161 job.status,
162 JobStatus.SUSPENDED)
163
164 def test_suspend_when_running(self):
165 """When a job is running, attempting to suspend is invalid."""
166 job = Job(_status=JobStatus.RUNNING)
167 self.assertRaises(InvalidTransition, job.suspend)
168
169 def test_suspend_when_completed(self):
170 """When a job is completed, attempting to suspend is invalid."""
171 job = Job(_status=JobStatus.COMPLETED)
172 self.assertRaises(InvalidTransition, job.suspend)
173
174 def test_suspend_when_failed(self):
175 """When a job is failed, attempting to suspend is invalid."""
176 job = Job(_status=JobStatus.FAILED)
177 self.assertRaises(InvalidTransition, job.suspend)
178
179 def test_resume(self):
180 """A job that is suspended can be resumed."""
181 job = Job(_status=JobStatus.SUSPENDED)
182 job.resume()
183 self.assertEqual(
184 job.status,
185 JobStatus.WAITING)
186
187 def test_resume_when_running(self):
188 """When a job is running, attempting to resume is invalid."""
189 job = Job(_status=JobStatus.RUNNING)
190 self.assertRaises(InvalidTransition, job.resume)
191
192 def test_resume_when_completed(self):
193 """When a job is completed, attempting to resume is invalid."""
194 job = Job(_status=JobStatus.COMPLETED)
195 self.assertRaises(InvalidTransition, job.resume)
196
197 def test_resume_when_failed(self):
198 """When a job is failed, attempting to resume is invalid."""
199 job = Job(_status=JobStatus.FAILED)
200 self.assertRaises(InvalidTransition, job.resume)
201
156202
157class TestReadiness(TestCase):203class TestReadiness(TestCase):
158 """Test the implementation of readiness."""204 """Test the implementation of readiness."""