1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
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
44
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
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
63 """
64 Empty the queue of actions.
65 """
66 self._tasks_queue = ThreadsafeList()
67
68 self._running = False
69
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
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
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
141 time.sleep(self.time_between_tasks)
142
143 self._running = False
144
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214