mirror of
https://github.com/nikdoof/test-auth.git
synced 2025-12-14 14:52:15 +00:00
Added django_cron
This commit is contained in:
35
django_cron/.svn/all-wcprops
Normal file
35
django_cron/.svn/all-wcprops
Normal 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
198
django_cron/.svn/entries
Normal 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
1
django_cron/.svn/format
Normal file
@@ -0,0 +1 @@
|
|||||||
|
9
|
||||||
54
django_cron/.svn/text-base/README.txt.svn-base
Normal file
54
django_cron/.svn/text-base/README.txt.svn-base
Normal 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/.svn/text-base/__init__.py.svn-base
Normal file
63
django_cron/.svn/text-base/__init__.py.svn-base
Normal 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/.svn/text-base/base.py.svn-base
Normal file
127
django_cron/.svn/text-base/base.py.svn-base
Normal 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/.svn/text-base/models.py.svn-base
Normal file
39
django_cron/.svn/text-base/models.py.svn-base
Normal 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/.svn/text-base/signals.py.svn-base
Normal file
26
django_cron/.svn/text-base/signals.py.svn-base
Normal 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
54
django_cron/README.txt
Normal 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
63
django_cron/__init__.py
Normal 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
127
django_cron/base.py
Normal 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
39
django_cron/models.py
Normal 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
26
django_cron/signals.py
Normal 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"])
|
||||||
@@ -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',
|
||||||
|
|||||||
Reference in New Issue
Block a user