Added django_cron

This commit is contained in:
dreddit
2010-02-27 19:02:08 +01:00
parent 0f2c57cd5a
commit 5c5a2622d0
14 changed files with 854 additions and 1 deletions

View File

@@ -0,0 +1,35 @@
K 25
svn:wc:ra_dav:version-url
V 34
/svn/!svn/ver/32/trunk/django_cron
END
base.py
K 25
svn:wc:ra_dav:version-url
V 42
/svn/!svn/ver/32/trunk/django_cron/base.py
END
__init__.py
K 25
svn:wc:ra_dav:version-url
V 46
/svn/!svn/ver/16/trunk/django_cron/__init__.py
END
signals.py
K 25
svn:wc:ra_dav:version-url
V 44
/svn/!svn/ver/8/trunk/django_cron/signals.py
END
models.py
K 25
svn:wc:ra_dav:version-url
V 44
/svn/!svn/ver/16/trunk/django_cron/models.py
END
README.txt
K 25
svn:wc:ra_dav:version-url
V 45
/svn/!svn/ver/16/trunk/django_cron/README.txt
END

198
django_cron/.svn/entries Normal file
View File

@@ -0,0 +1,198 @@
9
dir
32
http://django-cron.googlecode.com/svn/trunk/django_cron
http://django-cron.googlecode.com/svn
2009-10-28T14:21:55.477932Z
32
jim.mixtake@gmail.com
svn:special svn:externals svn:needs-lock
857153d3-df44-0410-aaef-ab1f86cdcd94
base.py
file
2010-02-20T20:20:49.000000Z
afab29654c6380b9c2ecd00fae92522c
2009-10-28T14:21:55.477932Z
32
jim.mixtake@gmail.com
4064
__init__.py
file
2010-02-20T20:20:49.000000Z
8492cf50017e7eff784fdfbe0cc8b3ba
2009-06-02T13:59:46.682354Z
16
Jim.mixtake
2566
signals.py
file
2010-02-20T20:20:49.000000Z
8e3eba63f720bd6d830fc89d7d6be693
2008-10-26T12:02:48.705921Z
5
digitalxero
1192
models.py
file
2010-02-20T20:20:49.000000Z
329f05f78f78465d4acfba95c42d32f7
2009-06-02T13:59:46.682354Z
16
Jim.mixtake
1632
README.txt
file
2010-02-20T20:20:49.000000Z
801836776103697e20d5d9a9446cb28b
2009-06-02T13:59:46.682354Z
16
Jim.mixtake
1953

1
django_cron/.svn/format Normal file
View File

@@ -0,0 +1 @@
9

View File

@@ -0,0 +1,54 @@
= How to install djang-cron =
1. Put 'django_cron' into your python path
2. Add 'django_cron' to INSTALLED_APPS in your settings.py file
3. Add the following code to the beginning of your urls.py file (just after the imports):
import django_cron
django_cron.autodiscover()
4. Create a file called 'cron.py' inside each installed app that you want to add a recurring job to. The app must be installed via the INSTALLED_APPS in your settings.py or the autodiscover will not find it.
=== Important note ===
If you are using mod_python, you need to make sure your server is set up to server more than one request per instance, Otherwise it will kill django-cron before the tasks get started. The specific line to look for is in your 'httpd.conf' file:
# THIS IS BAD!!! IT WILL CRIPPLE DJANGO-CRON
MaxRequestsPerChild 1
Change it to a value that is large enough that your cron jobs will get run at least once per instance. We're working on resolving this issue without dictating your server config.
In the meantime, django_cron is best used to execute tasks that occur relatively often (at least once an hour). Try setting MaxRequestsPerChild to 50, 100, or 200
# Depending on traffic, and your server config, a number between 50 and 500 is probably good
# Note: the higher this number, the more memory django is likely to use. Be careful on shared hosting
MaxRequestsPerChild 100
== Example cron.py ==
from django_cron import cronScheduler, Job
# This is a function I wrote to check a feedback email address
# and add it to our database. Replace with your own imports
from MyMailFunctions import check_feedback_mailbox
class CheckMail(Job):
"""
Cron Job that checks the lgr users mailbox and adds any
approved senders' attachments to the db
"""
# run every 300 seconds (5 minutes)
run_every = 300
def job(self):
# This will be executed every 5 minutes
check_feedback_mailbox()
cronScheduler.register(CheckMail)

View File

@@ -0,0 +1,63 @@
"""
Copyright (c) 2007-2008, Dj Gilcrease
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
from base import Job, cronScheduler
def autodiscover():
"""
Auto-discover INSTALLED_APPS cron.py modules and fail silently when
not present. This forces an import on them to register any cron jobs they
may want.
"""
import imp
from django.conf import settings
for app in settings.INSTALLED_APPS:
# For each app, we need to look for an cron.py inside that app's
# package. We can't use os.path here -- recall that modules may be
# imported different ways (think zip files) -- so we need to get
# the app's __path__ and look for cron.py on that path.
# Step 1: find out the app's __path__ Import errors here will (and
# should) bubble up, but a missing __path__ (which is legal, but weird)
# fails silently -- apps that do weird things with __path__ might
# need to roll their own cron registration.
try:
app_path = __import__(app, {}, {}, [app.split('.')[-1]]).__path__
except AttributeError:
continue
# Step 2: use imp.find_module to find the app's admin.py. For some
# reason imp.find_module raises ImportError if the app can't be found
# but doesn't actually try to import the module. So skip this app if
# its admin.py doesn't exist
try:
imp.find_module('cron', app_path)
except ImportError:
continue
# Step 3: import the app's cron file. If this has errors we want them
# to bubble up.
__import__("%s.cron" % app)
# Step 4: once we find all the cron jobs, start the cronScheduler
cronScheduler.execute()

View File

@@ -0,0 +1,127 @@
"""
Copyright (c) 2007-2008, Dj Gilcrease
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
import cPickle
from threading import Timer
from datetime import datetime
from django.dispatch import dispatcher
from django.conf import settings
from signals import cron_done
import models
# how often to check if jobs are ready to be run (in seconds)
# in reality if you have a multithreaded server, it may get checked
# more often that this number suggests, so keep an eye on it...
# default value: 300 seconds == 5 min
polling_frequency = getattr(settings, "CRON_POLLING_FREQUENCY", 300)
class Job(object):
# 86400 seconds == 24 hours
run_every = 86400
def run(self, *args, **kwargs):
self.job()
cron_done.send(sender=self, *args, **kwargs)
def job(self):
"""
Should be overridden (this way is cleaner, but the old way - overriding run() - will still work)
"""
pass
class CronScheduler(object):
def register(self, job_class, *args, **kwargs):
"""
Register the given Job with the scheduler class
"""
job_instance = job_class()
if not isinstance(job_instance, Job):
raise TypeError("You can only register a Job not a %r" % job_class)
job, created = models.Job.objects.get_or_create(name=str(job_instance.__class__))
if created:
job.instance = cPickle.dumps(job_instance)
job.args = cPickle.dumps(args)
job.kwargs = cPickle.dumps(kwargs)
job.run_frequency = job_instance.run_every
job.save()
def execute(self):
"""
Queue all Jobs for execution
"""
status, created = models.Cron.objects.get_or_create(pk=1)
# This is important for 2 reasons:
# 1. It keeps us for running more than one instance of the
# same job at a time
# 2. It reduces the number of polling threads because they
# get killed off if they happen to check while another
# one is already executing a job (only occurs with
# multi-threaded servers)
if status.executing:
return
status.executing = True
try:
status.save()
except:
# this will fail if you're debugging, so we want it
# to fail silently and start the timer again so we
# can pick up where we left off once debugging is done
Timer(polling_frequency, self.execute).start()
return
jobs = models.Job.objects.all()
for job in jobs:
if job.queued:
time_delta = datetime.now() - job.last_run
if (time_delta.seconds + 86400*time_delta.days) > job.run_frequency:
inst = cPickle.loads(str(job.instance))
args = cPickle.loads(str(job.args))
kwargs = cPickle.loads(str(job.kwargs))
try:
inst.run(*args, **kwargs)
job.last_run = datetime.now()
job.save()
except Exception:
# if the job throws an error, just remove it from
# the queue. That way we can find/fix the error and
# requeue the job manually
job.queued = False
job.save()
status.executing = False
status.save()
# Set up for this function to run again
Timer(polling_frequency, self.execute).start()
cronScheduler = CronScheduler()

View File

@@ -0,0 +1,39 @@
"""
Copyright (c) 2007-2008, Dj Gilcrease
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
from django.db import models
from datetime import datetime
class Job(models.Model):
name = models.CharField(max_length=100)
# time between job runs (in seconds) // default: 1 day
run_frequency = models.PositiveIntegerField(default=86400)
last_run = models.DateTimeField(default=datetime.now())
instance = models.TextField()
args = models.TextField()
kwargs = models.TextField()
queued = models.BooleanField(default=True)
class Cron(models.Model):
executing = models.BooleanField(default=False)

View File

@@ -0,0 +1,26 @@
"""
Copyright (c) 2007-2008, Dj Gilcrease
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
from django.dispatch import Signal
cron_queued = Signal()
cron_done = Signal(providing_args=["job"])

54
django_cron/README.txt Normal file
View File

@@ -0,0 +1,54 @@
= How to install djang-cron =
1. Put 'django_cron' into your python path
2. Add 'django_cron' to INSTALLED_APPS in your settings.py file
3. Add the following code to the beginning of your urls.py file (just after the imports):
import django_cron
django_cron.autodiscover()
4. Create a file called 'cron.py' inside each installed app that you want to add a recurring job to. The app must be installed via the INSTALLED_APPS in your settings.py or the autodiscover will not find it.
=== Important note ===
If you are using mod_python, you need to make sure your server is set up to server more than one request per instance, Otherwise it will kill django-cron before the tasks get started. The specific line to look for is in your 'httpd.conf' file:
# THIS IS BAD!!! IT WILL CRIPPLE DJANGO-CRON
MaxRequestsPerChild 1
Change it to a value that is large enough that your cron jobs will get run at least once per instance. We're working on resolving this issue without dictating your server config.
In the meantime, django_cron is best used to execute tasks that occur relatively often (at least once an hour). Try setting MaxRequestsPerChild to 50, 100, or 200
# Depending on traffic, and your server config, a number between 50 and 500 is probably good
# Note: the higher this number, the more memory django is likely to use. Be careful on shared hosting
MaxRequestsPerChild 100
== Example cron.py ==
from django_cron import cronScheduler, Job
# This is a function I wrote to check a feedback email address
# and add it to our database. Replace with your own imports
from MyMailFunctions import check_feedback_mailbox
class CheckMail(Job):
"""
Cron Job that checks the lgr users mailbox and adds any
approved senders' attachments to the db
"""
# run every 300 seconds (5 minutes)
run_every = 300
def job(self):
# This will be executed every 5 minutes
check_feedback_mailbox()
cronScheduler.register(CheckMail)

63
django_cron/__init__.py Normal file
View File

@@ -0,0 +1,63 @@
"""
Copyright (c) 2007-2008, Dj Gilcrease
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
from base import Job, cronScheduler
def autodiscover():
"""
Auto-discover INSTALLED_APPS cron.py modules and fail silently when
not present. This forces an import on them to register any cron jobs they
may want.
"""
import imp
from django.conf import settings
for app in settings.INSTALLED_APPS:
# For each app, we need to look for an cron.py inside that app's
# package. We can't use os.path here -- recall that modules may be
# imported different ways (think zip files) -- so we need to get
# the app's __path__ and look for cron.py on that path.
# Step 1: find out the app's __path__ Import errors here will (and
# should) bubble up, but a missing __path__ (which is legal, but weird)
# fails silently -- apps that do weird things with __path__ might
# need to roll their own cron registration.
try:
app_path = __import__(app, {}, {}, [app.split('.')[-1]]).__path__
except AttributeError:
continue
# Step 2: use imp.find_module to find the app's admin.py. For some
# reason imp.find_module raises ImportError if the app can't be found
# but doesn't actually try to import the module. So skip this app if
# its admin.py doesn't exist
try:
imp.find_module('cron', app_path)
except ImportError:
continue
# Step 3: import the app's cron file. If this has errors we want them
# to bubble up.
__import__("%s.cron" % app)
# Step 4: once we find all the cron jobs, start the cronScheduler
cronScheduler.execute()

127
django_cron/base.py Normal file
View File

@@ -0,0 +1,127 @@
"""
Copyright (c) 2007-2008, Dj Gilcrease
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
import cPickle
from threading import Timer
from datetime import datetime
from django.dispatch import dispatcher
from django.conf import settings
from signals import cron_done
import models
# how often to check if jobs are ready to be run (in seconds)
# in reality if you have a multithreaded server, it may get checked
# more often that this number suggests, so keep an eye on it...
# default value: 300 seconds == 5 min
polling_frequency = getattr(settings, "CRON_POLLING_FREQUENCY", 300)
class Job(object):
# 86400 seconds == 24 hours
run_every = 86400
def run(self, *args, **kwargs):
self.job()
cron_done.send(sender=self, *args, **kwargs)
def job(self):
"""
Should be overridden (this way is cleaner, but the old way - overriding run() - will still work)
"""
pass
class CronScheduler(object):
def register(self, job_class, *args, **kwargs):
"""
Register the given Job with the scheduler class
"""
job_instance = job_class()
if not isinstance(job_instance, Job):
raise TypeError("You can only register a Job not a %r" % job_class)
job, created = models.Job.objects.get_or_create(name=str(job_instance.__class__))
if created:
job.instance = cPickle.dumps(job_instance)
job.args = cPickle.dumps(args)
job.kwargs = cPickle.dumps(kwargs)
job.run_frequency = job_instance.run_every
job.save()
def execute(self):
"""
Queue all Jobs for execution
"""
status, created = models.Cron.objects.get_or_create(pk=1)
# This is important for 2 reasons:
# 1. It keeps us for running more than one instance of the
# same job at a time
# 2. It reduces the number of polling threads because they
# get killed off if they happen to check while another
# one is already executing a job (only occurs with
# multi-threaded servers)
if status.executing:
return
status.executing = True
try:
status.save()
except:
# this will fail if you're debugging, so we want it
# to fail silently and start the timer again so we
# can pick up where we left off once debugging is done
Timer(polling_frequency, self.execute).start()
return
jobs = models.Job.objects.all()
for job in jobs:
if job.queued:
time_delta = datetime.now() - job.last_run
if (time_delta.seconds + 86400*time_delta.days) > job.run_frequency:
inst = cPickle.loads(str(job.instance))
args = cPickle.loads(str(job.args))
kwargs = cPickle.loads(str(job.kwargs))
try:
inst.run(*args, **kwargs)
job.last_run = datetime.now()
job.save()
except Exception:
# if the job throws an error, just remove it from
# the queue. That way we can find/fix the error and
# requeue the job manually
job.queued = False
job.save()
status.executing = False
status.save()
# Set up for this function to run again
Timer(polling_frequency, self.execute).start()
cronScheduler = CronScheduler()

39
django_cron/models.py Normal file
View File

@@ -0,0 +1,39 @@
"""
Copyright (c) 2007-2008, Dj Gilcrease
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
from django.db import models
from datetime import datetime
class Job(models.Model):
name = models.CharField(max_length=100)
# time between job runs (in seconds) // default: 1 day
run_frequency = models.PositiveIntegerField(default=86400)
last_run = models.DateTimeField(default=datetime.now())
instance = models.TextField()
args = models.TextField()
kwargs = models.TextField()
queued = models.BooleanField(default=True)
class Cron(models.Model):
executing = models.BooleanField(default=False)

26
django_cron/signals.py Normal file
View File

@@ -0,0 +1,26 @@
"""
Copyright (c) 2007-2008, Dj Gilcrease
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
from django.dispatch import Signal
cron_queued = Signal()
cron_done = Signal(providing_args=["job"])

View File

@@ -45,7 +45,7 @@ USE_I18N = True
# Absolute path to the directory that holds media. # Absolute path to the directory that holds media.
# Example: "/home/media/media.lawrence.com/" # Example: "/home/media/media.lawrence.com/"
MEDIA_ROOT = '/home/nikdoof/dev/corpsso/media' MEDIA_ROOT = '/home/dreddit/www/login.dredd.it/login/media'
# URL that handles the media served from MEDIA_ROOT. Make sure to use a # URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash if there is a path component (optional in other cases). # trailing slash if there is a path component (optional in other cases).
@@ -86,6 +86,7 @@ INSTALLED_APPS = (
'django.contrib.sessions', 'django.contrib.sessions',
'django.contrib.sites', 'django.contrib.sites',
'registration', 'registration',
'django_cron',
'eve_proxy', 'eve_proxy',
'eve_api', 'eve_api',
'mumble', 'mumble',