Package elisa :: Package core :: Package utils :: Module deferred_action
[hide private]
[frames] | no frames]

Source Code for Module elisa.core.utils.deferred_action

  1  # -*- coding: utf-8 -*- 
  2  # Elisa - Home multimedia server 
  3  # Copyright (C) 2006-2008 Fluendo Embedded S.L. (www.fluendo.com). 
  4  # All rights reserved. 
  5  # 
  6  # This file is available under one of two license agreements. 
  7  # 
  8  # This file is licensed under the GPL version 3. 
  9  # See "LICENSE.GPL" in the root of this distribution including a special 
 10  # exception to use Elisa with Fluendo's plugins. 
 11  # 
 12  # The GPL part of Elisa is also available under a commercial licensing 
 13  # agreement from Fluendo. 
 14  # See "LICENSE.Elisa" in the root directory of this distribution package 
 15  # for details on that license. 
 16   
 17  __maintainer__ = 'Florian Boucault <florian@fluendo.com>' 
 18   
 19  from twisted.internet import defer, reactor 
 20  from twisted.python import failure 
 21  from threadsafe_list import ThreadsafeList 
 22  import time 
 23  from elisa.core import log 
 24   
25 -class DeferredActionsManager(log.Loggable):
26 27 """ 28 Manage a queue of actions (callables), and execute them sequentially in 29 a single thread. 30 31 WARNING: It is NOT thread-safe. 32 """ 33 34
35 - def __init__(self):
36 log.Loggable.__init__(self) 37 38 self._tasks_queue = ThreadsafeList() 39 # NOTE: self._running accesses are not protected by locks 40 # which means that start, stop and enqueue_action should not 41 # be called by different threads 42 self._running = False 43 self.time_between_tasks = 0
44
45 - def start(self):
46 """ 47 Start processing the actions in a separate thread 48 if it was not already the case. 49 """ 50 if self._running == False: 51 self._running = True 52 self.debug("Starting") 53 reactor.callInThread(self._main_loop)
54
55 - def stop(self):
56 """ 57 Stop processing the actions. The thread is stopped as soon as possible. 58 """ 59 self.debug("Stopping") 60 self.remove_all_actions()
61
62 - def remove_all_actions(self):
63 """ 64 Empty the queue of actions. 65 """ 66 self._tasks_queue = ThreadsafeList() 67 68 self._running = False
69
70 - def enqueue_action(self, action, *args, **kwargs):
71 """ 72 Add an action at the end of the queue. It will be processed when all the previous 73 actions in the queue have finished. If no actions are being processed, 74 it starts processing automatically. 75 76 WARNING: The program will not stop until the current task 77 has finished. 78 79 :parameters: 80 `action` : callable 81 Action to be executed 82 `args` : list 83 Arguments passed to the action 84 `kwargs` : dictionary 85 Keywords arguments passed to the action 86 87 :return: Deferred object used to chain success and error callbacks 88 :rtype: twisted.internet.defer.Deferred 89 """ 90 deferred = defer.Deferred() 91 self._tasks_queue.append((action, args, kwargs, deferred)) 92 93 if self._running == False: 94 self.start() 95 96 return deferred
97
98 - def insert_action(self, rank, action, *args, **kwargs):
99 """ 100 FIXME, DOCME: wrong documentation copied/pasted from enqueue_action 101 102 Add an action at the end of the queue. It will be processed when all the previous 103 actions in the queue have finished. If no actions are being processed, 104 it starts processing automatically. 105 106 WARNING: The program will not stop until the current task 107 has finished. 108 109 :parameters: 110 `action` : callable 111 Action to be executed 112 `args` : list 113 Arguments passed to the action 114 `kwargs` : dictionary 115 Keywords arguments passed to the action 116 117 :return: Deferred object used to chain success and error callbacks 118 :rtype: twisted.internet.defer.Deferred 119 """ 120 deferred = defer.Deferred() 121 self._tasks_queue.insert(rank, (action, args, kwargs, deferred)) 122 123 if self._running == False: 124 self.start() 125 126 return deferred
127
128 - def _main_loop(self):
129 """ 130 Process all the actions in the queue sequentially. 131 """ 132 # FIXME: reactor.running behaviour is not clear 133 while reactor.running: 134 if len(self._tasks_queue) == 0: 135 break 136 137 task = self._tasks_queue.pop(0) 138 self._execute_task(task) 139 140 #if self.time_between_tasks > 0: 141 time.sleep(self.time_between_tasks) 142 143 self._running = False
144
145 - def _execute_task(self, task):
146 """ 147 Process a single action. 148 149 :parameters: 150 `task` : (callable, list, dictionary, twisted.internet.defer.Deferred) 151 Action to be processed and associated deferred object 152 """ 153 154 action = task[0] 155 args = task[1] 156 kwargs = task[2] 157 deferred = task[3] 158 159 self.debug("execute task %r", task) 160 try: 161 result = action(*args, **kwargs) 162 except Exception, exc: 163 self.debug("failed: %r", exc) 164 f = failure.Failure() 165 reactor.callFromThread(deferred.errback, f) 166 else: 167 self.debug("result: %r", result) 168 reactor.callFromThread(deferred.callback, result)
169 170 171 #if __name__ == "__main__": 172 # import time 173 # 174 # mng = DeferredActionsManager() 175 # 176 # def f(): 177 # print "f called" 178 # time.sleep(2) 179 # return 51 180 # 181 # def g(x, y): 182 # print "g called" 183 # time.sleep(2) 184 # return x+y 185 # 186 # def display(x): 187 # print "display called:", x 188 # 189 # def test1(): 190 # dfr = mng.enqueue_action(f) 191 # dfr.addCallback(display) 192 # time.sleep(1) 193 # 194 # dfr = mng.enqueue_action(f) 195 # dfr.addCallback(display) 196 # 197 # dfr = mng.enqueue_action(g, 4, 8) 198 # dfr.addCallback(display) 199 # 200 # print "end of queue creation" 201 # 202 # def test2(): 203 # for i in xrange(10): 204 # #dfr = mng.enqueue_action(f) 205 # dfr = mng.enqueue_action(g, 2, 3) 206 # dfr.addCallback(display) 207 # 208 # print "end of queue creation" 209 # 210 # reactor.callWhenRunning(test1) 211 # reactor.run() 212 # 213 # print "quit" 214