Prevent `Queue#dequeue` from blowing the stack

In the case of many sequential jobs having been deleted, a recursive
implementation of `Queue#dequeue` is prone to blowing the stack in the
absence of tail-recursion support. Change the implementation from
recursive to iterative to work around this issue in CPython.
main
Tamir Duberstein 10 years ago
parent 5cb873b438
commit 985a2664a4

@ -329,6 +329,7 @@ class Queue(object):
Returns a job_class instance, which can be executed or inspected. Returns a job_class instance, which can be executed or inspected.
""" """
while True:
job_id = self.pop_job_id() job_id = self.pop_job_id()
if job_id is None: if job_id is None:
return None return None
@ -336,8 +337,7 @@ class Queue(object):
job = self.job_class.fetch(job_id, connection=self.connection) job = self.job_class.fetch(job_id, connection=self.connection)
except NoSuchJobError as e: except NoSuchJobError as e:
# Silently pass on jobs that don't exist (anymore), # Silently pass on jobs that don't exist (anymore),
# and continue by reinvoking itself recursively continue
return self.dequeue()
except UnpickleError as e: except UnpickleError as e:
# Attach queue information on the exception for improved error # Attach queue information on the exception for improved error
# reporting # reporting

@ -173,6 +173,14 @@ class TestQueue(RQTestCase):
# ...and assert the queue count when down # ...and assert the queue count when down
self.assertEquals(q.count, 0) self.assertEquals(q.count, 0)
def test_dequeue_deleted_jobs(self):
"""Dequeueing deleted jobs from queues don't blow the stack."""
q = Queue()
for _ in range(1,1000):
job = q.enqueue(say_hello)
job.delete()
q.dequeue()
def test_dequeue_instance_method(self): def test_dequeue_instance_method(self):
"""Dequeueing instance method jobs from queues.""" """Dequeueing instance method jobs from queues."""
q = Queue() q = Queue()

Loading…
Cancel
Save