|
1 | | -from tests import PyResTests, Basic, TestProcess, ErrorObject |
| 1 | +from tests import PyResTests, Basic, TestProcess, ErrorObject, RetryOnExceptionJob |
2 | 2 | from pyres import ResQ |
3 | 3 | from pyres.job import Job |
| 4 | +from pyres.scheduler import Scheduler |
4 | 5 | from pyres.worker import Worker |
5 | 6 | import os |
6 | 7 | import time |
| 8 | +import datetime |
| 9 | + |
| 10 | + |
7 | 11 | class WorkerTests(PyResTests): |
8 | 12 | def test_worker_init(self): |
9 | 13 | from pyres.exceptions import NoQueueError |
@@ -173,3 +177,54 @@ def test_prune_dead_workers(self): |
173 | 177 | # the assertion below should hold, because the workers we registered above are on a |
174 | 178 | # different host, and thus should not be pruned by this process |
175 | 179 | assert self.redis.scard('resque:workers') == 3 |
| 180 | + |
| 181 | + def test_retry_on_exception(self): |
| 182 | + now = datetime.datetime.now() |
| 183 | + self.set_current_time(now) |
| 184 | + worker = Worker(['basic']) |
| 185 | + scheduler = Scheduler() |
| 186 | + |
| 187 | + # queue up a job that will fail for 30 seconds |
| 188 | + self.resq.enqueue(RetryOnExceptionJob, |
| 189 | + now + datetime.timedelta(seconds=30)) |
| 190 | + worker.process() |
| 191 | + assert worker.get_failed() == 0 |
| 192 | + |
| 193 | + # check it retries the first time |
| 194 | + self.set_current_time(now + datetime.timedelta(seconds=5)) |
| 195 | + scheduler.handle_delayed_items() |
| 196 | + assert None == worker.process() |
| 197 | + assert worker.get_failed() == 0 |
| 198 | + |
| 199 | + # check it runs fine when it's stopped crashing |
| 200 | + self.set_current_time(now + datetime.timedelta(seconds=60)) |
| 201 | + scheduler.handle_delayed_items() |
| 202 | + assert True == worker.process() |
| 203 | + assert worker.get_failed() == 0 |
| 204 | + |
| 205 | + def test_retries_give_up_eventually(self): |
| 206 | + now = datetime.datetime.now() |
| 207 | + self.set_current_time(now) |
| 208 | + worker = Worker(['basic']) |
| 209 | + scheduler = Scheduler() |
| 210 | + |
| 211 | + # queue up a job that will fail for 60 seconds |
| 212 | + self.resq.enqueue(RetryOnExceptionJob, |
| 213 | + now + datetime.timedelta(seconds=60)) |
| 214 | + worker.process() |
| 215 | + assert worker.get_failed() == 0 |
| 216 | + |
| 217 | + # check it retries the first time |
| 218 | + self.set_current_time(now + datetime.timedelta(seconds=5)) |
| 219 | + scheduler.handle_delayed_items() |
| 220 | + assert None == worker.process() |
| 221 | + assert worker.get_failed() == 0 |
| 222 | + |
| 223 | + # check it fails when we've been trying too long |
| 224 | + self.set_current_time(now + datetime.timedelta(seconds=20)) |
| 225 | + scheduler.handle_delayed_items() |
| 226 | + assert None == worker.process() |
| 227 | + assert worker.get_failed() == 1 |
| 228 | + |
| 229 | + def set_current_time(self, time): |
| 230 | + ResQ._current_time = staticmethod(lambda: time) |
0 commit comments