| 
					
				 | 
			
			
				@@ -0,0 +1,152 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+from celery import registry 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+from datetime import datetime 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+from UserDict import UserDict 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+from celery.serialization import pickle 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import atexit 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import errno 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import time 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+schedule = PersistentDict(save_at_exit=True) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+class ScheduleEntry(object): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    """An entry in the scheduler. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    :param task: The task class. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    :keyword last_run_at: The time and date when this task was last run. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    :keyword total_run_count: Total number of times this periodic task has 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        been executed. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    """ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def __init__(self, task, last_run_at=None, total_run_count=None) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self.task = task 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self.last_run_at = None 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self.total_run_count = None 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def execute(self): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        try: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            result = self.task.apply_async() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        except Exception, exc: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            print("Couldn't apply scheduled task %s: %s" % ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                self.task.name, exc)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            result = None 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self.last_run_at = datetime.now() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self.total_run_count += 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return result 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def is_due(self): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        run_at = self.last_run_at + self.task.run_every 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return True if datetime.now() > self.last_run_at else return False 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+class Scheduler(object): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    """Scheduler for periodic tasks. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    :keyword registry: The task registry to use. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    :keyword schedule: The schedule dictionary. Default is the global 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        persistent schedule ``celery.beat.schedule``. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    """ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    registry = registry.tasks 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    data = schedule 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def __init__(self, registry=None, schedule=None): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self.registry = registry or self.registry 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self.data = schedule or self.data 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self.schedule_registry() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def run(self): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        """Run the scheduler. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        This runs :meth:`tick` every second in a never-exit loop.""" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        while True: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            self.tick()  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            time.sleep(1) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def tick(self): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        """Run a tick, that is one iteration of the scheduler. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Executes all due tasks.""" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return [(entry.task, entry.execute()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    for entry in self.get_due_tasks()] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def get_due_tasks(self): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        """Get all the schedule entries that are due to execution.""" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return filter(lambda entry: entry.is_due(), self.schedule.values()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def schedule_registry(self): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        """Add the current contents of the registry to the schedule.""" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        periodic_tasks = self.registry.get_all_periodic() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        schedule = dict((name, tasktimetuple(task)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            for name, task in periodic_tasks.items()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self.schedule = dict(schedule, **self.schedule) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @property 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def schedule(self): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return self.data 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+class PersistentDict(UserDict): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    """Dictionary that can be stored to disk. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    :param filename: Name of the file to save to. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    :keyword initial_data: Initial dict to start with. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    :keyword save_at_exit: Register an atexit handler to automatically save 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        the data when the program exits (not safe, but as an extra precaution) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    :keyword encoding: The encoding to write the file with, default is 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ``"zlib"``. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    """ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    encoding = "zlib" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    save_at_exit = False 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def __init__(self, filename, initial_data=None, save_at_exit=None, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            encoding=None): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self.data = initial_data or {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self.filename = filename 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self.encoding = encoding 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if save_at_exit is not None: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            self.save_at_exit = save_at_exit 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self.reload() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self._saved = False 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self.save_at_exit and self.register_atexit() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def reload(self): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        """Reload data from disk.""" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        persisted_data = self._read_file(self.filename, self.encoding) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self.data = dict(self.data, **persisted_data) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def save(self): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        """Save data to disk.""" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self._saved = True 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        encoded = pickle.dump(fh, self.data).encode(self.encoding) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        fh = open(self.filename, "w") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        try: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            fh.write(encoded) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        finally: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            fh.close() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def register_atexit(self): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        """Register an atexit handler to save data to disk when the 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        program terminates.""" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        atexit.register(self._save_atexit) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def _save_atexit(self): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        self._saved or self.save() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    def _read_file(self, filename, encoding): 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        try: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            fh = open(filename) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        except IOError, exc: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if exc.errno == errno.ENOENT: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            raise 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        try: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return pickle.loads(fh.read().decode(encoding)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        finally: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            fh.close() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 |