Simplify the persistence of jobs.

Fixes #23 and #24.
main
Vincent Driessen 13 years ago
parent bffe6cbbde
commit 7c903e45ef

@ -131,21 +131,53 @@ class Job(object):
Will raise a NoSuchJobError if no corresponding Redis key exists.
"""
key = self.key
pickled_data = conn.hget(key, 'data')
if pickled_data is None:
properties = ['data', 'created_at', 'origin', 'description',
'enqueued_at', 'ended_at', 'result', 'exc_info']
data, created_at, origin, description, \
enqueued_at, ended_at, result, \
exc_info = conn.hmget(key, properties)
if data is None:
raise NoSuchJobError('No such job: %s' % (key,))
self.origin = conn.hget(key, 'origin')
def to_date(date_str):
if date_str is None:
return None
else:
return times.to_universal(date_str)
self._func, self._args, self._kwargs = unpickle(data)
self.created_at = times.to_universal(conn.hget(key, 'created_at'))
self.created_at = to_date(created_at)
self.origin = origin
self.description = description
self.enqueued_at = to_date(enqueued_at)
self.ended_at = to_date(ended_at)
self.result = result
self.exc_info = exc_info
def save(self):
"""Persists the current job instance to its corresponding Redis key."""
key = self.key
conn.hset(key, 'data', pickled_data)
conn.hset(key, 'origin', self.origin)
conn.hset(key, 'created_at', times.format(self.created_at, 'UTC'))
obj = {}
obj['created_at'] = times.format(self.created_at, 'UTC')
if self.func is not None:
obj['data'] = dumps(self.job_tuple)
if self.origin is not None:
obj['origin'] = self.origin
if self.description is not None:
obj['description'] = self.description
if self.enqueued_at is not None:
obj['enqueued_at'] = times.format(self.enqueued_at, 'UTC')
if self.ended_at is not None:
obj['ended_at'] = times.format(self.ended_at, 'UTC')
if self.result is not None:
obj['result'] = self.result
if self.exc_info is not None:
obj['exc_info'] = self.exc_info
conn.hmset(key, obj)
# Job execution

@ -0,0 +1,6 @@
import times
def strip_milliseconds(date):
return times.to_universal(times.format(date, 'UTC'))

@ -1,5 +1,7 @@
import times
from datetime import datetime
from tests import RQTestCase
from tests.helpers import strip_milliseconds
from pickle import loads
from rq.job import Job
from rq.exceptions import NoSuchJobError, UnpickleError
@ -14,28 +16,28 @@ class TestJob(RQTestCase):
"""Creation of new empty jobs."""
job = Job()
# Jobs have a random UUID
# Jobs have a random UUID and a creation date
self.assertIsNotNone(job.id)
# Jobs have no data yet...
self.assertEquals(job.func, None)
self.assertEquals(job.args, None)
self.assertEquals(job.kwargs, None)
self.assertEquals(job.origin, None)
self.assertEquals(job.enqueued_at, None)
self.assertEquals(job.result, None)
self.assertEquals(job.exc_info, None)
# ...except for a created_at property
self.assertIsNotNone(job.created_at)
def test_create_normal_job(self):
# ...and nothing else
self.assertIsNone(job.func, None)
self.assertIsNone(job.args, None)
self.assertIsNone(job.kwargs, None)
self.assertIsNone(job.origin, None)
self.assertIsNone(job.enqueued_at, None)
self.assertIsNone(job.ended_at, None)
self.assertIsNone(job.result, None)
self.assertIsNone(job.exc_info, None)
def test_create_typical_job(self):
"""Creation of jobs for function calls."""
job = Job.for_call(arbitrary_function, 3, 4, z=2)
# Jobs have a random UUID
self.assertIsNotNone(job.id)
self.assertIsNotNone(job.created_at)
self.assertIsNotNone(job.description)
# Job data is set...
self.assertEquals(job.func, arbitrary_function)
@ -76,8 +78,39 @@ class TestJob(RQTestCase):
self.assertEquals(job.created_at, datetime(2012, 2, 7, 22, 13, 24))
def test_persistence_of_jobs(self):
"""Storing and fetching of jobs."""
def test_persistence_of_empty_jobs(self):
"""Storing empty jobs."""
job = Job()
job.save()
expected_date = strip_milliseconds(job.created_at)
stored_date = self.testconn.hget(job.key, 'created_at')
self.assertEquals(
times.to_universal(stored_date),
expected_date)
# ... and no other keys are stored
self.assertItemsEqual(
self.testconn.hkeys(job.key),
['created_at'])
def test_persistence_of_typical_jobs(self):
"""Storing typical jobs."""
job = Job.for_call(arbitrary_function, 3, 4, z=2)
job.save()
expected_date = strip_milliseconds(job.created_at)
stored_date = self.testconn.hget(job.key, 'created_at')
self.assertEquals(
times.to_universal(stored_date),
expected_date)
# ... and no other keys are stored
self.assertItemsEqual(
self.testconn.hkeys(job.key),
['created_at', 'data', 'description'])
def test_store_then_fetch(self):
job = Job.for_call(arbitrary_function, 3, 4, z=2)
job.save()
@ -94,9 +127,8 @@ class TestJob(RQTestCase):
with self.assertRaises(NoSuchJobError):
Job.fetch('b4a44d44-da16-4620-90a6-798e8cd72ca0')
def test_dequeue_unreadable_data(self):
"""Dequeue fails on unreadable data."""
def test_fetching_unreadable_data(self):
"""Fetching fails on unreadable data."""
# Set up
job = Job.for_call(arbitrary_function, 3, 4, z=2)
job.save()

@ -1,5 +1,6 @@
from tests import RQTestCase
from tests import testjob, failing_job
from tests.helpers import strip_milliseconds
from rq import Queue, Worker
from rq.job import Job

Loading…
Cancel
Save