mirror of https://github.com/rq/rq.git
Refactor the .enqueue() API to not gobble the timeout kwargs.
This fixes #98.
This commit is contained in:
parent
8436d9b2c8
commit
f6e67431d7
|
@ -50,11 +50,16 @@ class Job(object):
|
|||
|
||||
# Job construction
|
||||
@classmethod
|
||||
def create(cls, func, *args, **kwargs):
|
||||
def create(cls, func, args=None, kwargs=None, connection=None):
|
||||
"""Creates a new Job instance for the given function, arguments, and
|
||||
keyword arguments.
|
||||
"""
|
||||
connection = kwargs.pop('connection', None)
|
||||
if args is None:
|
||||
args = ()
|
||||
if kwargs is None:
|
||||
kwargs = {}
|
||||
assert isinstance(args, tuple), '%r is not a valid args list.' % (args,)
|
||||
assert isinstance(kwargs, dict), '%r is not a valid kwargs dict.' % (kwargs,)
|
||||
job = cls(connection=connection)
|
||||
if inspect.ismethod(func):
|
||||
job._instance = func.im_self
|
||||
|
|
32
rq/queue.py
32
rq/queue.py
|
@ -107,25 +107,43 @@ class Queue(object):
|
|||
"""Pushes a job ID on the corresponding Redis queue."""
|
||||
self.connection.rpush(self.key, job_id)
|
||||
|
||||
def enqueue_call(self, func, args, kwargs, **options):
|
||||
"""Creates a job to represent the delayed function call and enqueues
|
||||
it.
|
||||
|
||||
It is much like `.enqueue()`, except that it takes the function's args
|
||||
and kwargs as explicit arguments. Any kwargs passed to this function
|
||||
contain options for RQ itself.
|
||||
"""
|
||||
timeout = options.get('timeout', self._default_timeout)
|
||||
job = Job.create(func, args, kwargs, connection=self.connection)
|
||||
return self.enqueue_job(job, timeout=timeout)
|
||||
|
||||
def enqueue(self, f, *args, **kwargs):
|
||||
"""Creates a job to represent the delayed function call and enqueues
|
||||
it.
|
||||
|
||||
Expects the function to call, along with the arguments and keyword
|
||||
arguments. May be a fully qualified string of the function instance,
|
||||
in which case the function must be meaningful to the worker.
|
||||
arguments.
|
||||
|
||||
The special keyword `timeout` is reserved for `enqueue()` itself and
|
||||
it won't be passed to the actual job function.
|
||||
The function argument `f` may be any of the following:
|
||||
|
||||
* A reference to a function
|
||||
* A reference to an object's instance method
|
||||
* A string, representing the location of a function (must be
|
||||
meaningful to the import context of the workers)
|
||||
"""
|
||||
if not isinstance(f, basestring) and f.__module__ == '__main__':
|
||||
raise ValueError(
|
||||
'Functions from the __main__ module cannot be processed '
|
||||
'by workers.')
|
||||
|
||||
timeout = kwargs.pop('timeout', self._default_timeout)
|
||||
job = Job.create(f, *args, connection=self.connection, **kwargs)
|
||||
return self.enqueue_job(job, timeout=timeout)
|
||||
options = {}
|
||||
try:
|
||||
options['timeout'] = kwargs.pop('timeout')
|
||||
except KeyError:
|
||||
pass
|
||||
return self.enqueue_call(func=f, args=args, kwargs=kwargs, **options)
|
||||
|
||||
def enqueue_job(self, job, timeout=None, set_meta_data=True):
|
||||
"""Enqueues a job for delayed execution.
|
||||
|
|
|
@ -30,7 +30,7 @@ class TestJob(RQTestCase):
|
|||
|
||||
def test_create_typical_job(self):
|
||||
"""Creation of jobs for function calls."""
|
||||
job = Job.create(some_calculation, 3, 4, z=2)
|
||||
job = Job.create(func=some_calculation, args=(3, 4), kwargs=dict(z=2))
|
||||
|
||||
# Jobs have a random UUID
|
||||
self.assertIsNotNone(job.id)
|
||||
|
@ -51,7 +51,7 @@ class TestJob(RQTestCase):
|
|||
def test_create_instance_method_job(self):
|
||||
"""Creation of jobs for instance methods."""
|
||||
c = Calculator(2)
|
||||
job = Job.create(c.calculate, 3, 4)
|
||||
job = Job.create(func=c.calculate, args=(3, 4))
|
||||
|
||||
# Job data is set
|
||||
self.assertEquals(job.func, c.calculate)
|
||||
|
@ -60,7 +60,7 @@ class TestJob(RQTestCase):
|
|||
|
||||
def test_create_job_from_string_function(self):
|
||||
"""Creation of jobs using string specifier."""
|
||||
job = Job.create('tests.fixtures.say_hello', 'World')
|
||||
job = Job.create(func='tests.fixtures.say_hello', args=('World',))
|
||||
|
||||
# Job data is set
|
||||
self.assertEquals(job.func, say_hello)
|
||||
|
@ -69,7 +69,7 @@ class TestJob(RQTestCase):
|
|||
|
||||
def test_save(self): # noqa
|
||||
"""Storing jobs."""
|
||||
job = Job.create(some_calculation, 3, 4, z=2)
|
||||
job = Job.create(func=some_calculation, args=(3, 4), kwargs=dict(z=2))
|
||||
|
||||
# Saving creates a Redis hash
|
||||
self.assertEquals(self.testconn.exists(job.key), False)
|
||||
|
@ -116,7 +116,7 @@ class TestJob(RQTestCase):
|
|||
|
||||
def test_persistence_of_typical_jobs(self):
|
||||
"""Storing typical jobs."""
|
||||
job = Job.create(some_calculation, 3, 4, z=2)
|
||||
job = Job.create(func=some_calculation, args=(3, 4), kwargs=dict(z=2))
|
||||
job.save()
|
||||
|
||||
expected_date = strip_milliseconds(job.created_at)
|
||||
|
@ -132,7 +132,7 @@ class TestJob(RQTestCase):
|
|||
|
||||
def test_store_then_fetch(self):
|
||||
"""Store, then fetch."""
|
||||
job = Job.create(some_calculation, 3, 4, z=2)
|
||||
job = Job.create(func=some_calculation, args=(3, 4), kwargs=dict(z=2))
|
||||
job.save()
|
||||
|
||||
job2 = Job.fetch(job.id)
|
||||
|
@ -151,7 +151,7 @@ class TestJob(RQTestCase):
|
|||
def test_fetching_unreadable_data(self):
|
||||
"""Fetching fails on unreadable data."""
|
||||
# Set up
|
||||
job = Job.create(some_calculation, 3, 4, z=2)
|
||||
job = Job.create(func=some_calculation, args=(3, 4), kwargs=dict(z=2))
|
||||
job.save()
|
||||
|
||||
# Just replace the data hkey with some random noise
|
||||
|
@ -161,7 +161,7 @@ class TestJob(RQTestCase):
|
|||
|
||||
def test_job_is_unimportable(self):
|
||||
"""Jobs that cannot be imported throw exception on access."""
|
||||
job = Job.create(say_hello, 'Lionel')
|
||||
job = Job.create(func=say_hello, args=('Lionel',))
|
||||
job.save()
|
||||
|
||||
# Now slightly modify the job to make it unimportable (this is
|
||||
|
@ -181,7 +181,7 @@ class TestJob(RQTestCase):
|
|||
- Saved in Redis when job.save() is called
|
||||
- Attached back to job instance when job.refresh() is called
|
||||
"""
|
||||
job = Job.create(say_hello, 'Lionel')
|
||||
job = Job.create(func=say_hello, args=('Lionel',))
|
||||
job.foo = 'bar'
|
||||
job.save()
|
||||
self.assertEqual(self.testconn.hget(job.key, 'foo'), 'bar')
|
||||
|
|
|
@ -86,7 +86,7 @@ class TestQueue(RQTestCase):
|
|||
def test_enqueue_sets_metadata(self):
|
||||
"""Enqueueing job onto queues modifies meta data."""
|
||||
q = Queue()
|
||||
job = Job.create(say_hello, 'Nick', foo='bar')
|
||||
job = Job.create(func=say_hello, args=('Nick',), kwargs=dict(foo='bar'))
|
||||
|
||||
# Preconditions
|
||||
self.assertIsNone(job.origin)
|
||||
|
@ -209,7 +209,7 @@ class TestQueue(RQTestCase):
|
|||
class TestFailedQueue(RQTestCase):
|
||||
def test_requeue_job(self):
|
||||
"""Requeueing existing jobs."""
|
||||
job = Job.create(div_by_zero, 1, 2, 3)
|
||||
job = Job.create(func=div_by_zero, args=(1, 2, 3))
|
||||
job.origin = 'fake'
|
||||
job.save()
|
||||
get_failed_queue().quarantine(job, Exception('Some fake error')) # noqa
|
||||
|
@ -233,7 +233,7 @@ class TestFailedQueue(RQTestCase):
|
|||
|
||||
def test_quarantine_preserves_timeout(self):
|
||||
"""Quarantine preserves job timeout."""
|
||||
job = Job.create(div_by_zero, 1, 2, 3)
|
||||
job = Job.create(func=div_by_zero, args=(1, 2, 3))
|
||||
job.origin = 'fake'
|
||||
job.timeout = 200
|
||||
job.save()
|
||||
|
@ -243,7 +243,7 @@ class TestFailedQueue(RQTestCase):
|
|||
|
||||
def test_requeueing_preserves_timeout(self):
|
||||
"""Requeueing preserves job timeout."""
|
||||
job = Job.create(div_by_zero, 1, 2, 3)
|
||||
job = Job.create(func=div_by_zero, args=(1, 2, 3))
|
||||
job.origin = 'fake'
|
||||
job.timeout = 200
|
||||
job.save()
|
||||
|
|
|
@ -45,7 +45,7 @@ class TestWorker(RQTestCase):
|
|||
# NOTE: We have to fake this enqueueing for this test case.
|
||||
# What we're simulating here is a call to a function that is not
|
||||
# importable from the worker process.
|
||||
job = Job.create(div_by_zero, 3)
|
||||
job = Job.create(func=div_by_zero, args=(3,))
|
||||
job.save()
|
||||
data = self.testconn.hget(job.key, 'data')
|
||||
invalid_data = data.replace('div_by_zero', 'nonexisting_job')
|
||||
|
|
Loading…
Reference in New Issue