1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """cancellable, periodic call to a procedure
23 """
24
25 from twisted.internet import reactor
26 from twisted.internet.defer import maybeDeferred
27
28 from flumotion.common import log
29
30 __version__ = "$Rev$"
31
32
33 -class Poller(object, log.Loggable):
34 """A class representing a cancellable, periodic call to a procedure,
35 which is robust in the face of exceptions raised by the procedure.
36
37 The poller will wait for a specified number of seconds between
38 calls. The time taken for the procedure to complete is not counted
39 in the timeout. If the procedure returns a deferred, rescheduling
40 will be performed after the deferred fires.
41
42 For example, if the timeout is 10 seconds and the procedure returns
43 a deferred which fires 5 seconds later, the next invocation of the
44 procedure will be performed 15 seconds after the previous
45 invocation.
46 """
47
48 - def __init__(self, proc, timeout, immediately=False, start=True):
49 """
50 @param proc: a procedure of no arguments
51 @param timeout: float number of seconds to wait between calls
52 @param immediately: whether to immediately call proc, or to wait
53 until one period has passed
54 @param start: whether to start the poller (defaults to True)
55 """
56
57 self.proc = proc
58 self.logName = 'poller-%s' % proc.__name__
59 self.timeout = timeout
60
61 self._dc = None
62 self.running = False
63
64 if start:
65 self.start(immediately)
66
67 - def start(self, immediately=False):
68 """Start the poller.
69
70 This procedure is called during __init__, so it is normally not
71 necessary to call it. It will ensure that the poller is running,
72 even after a previous call to stop().
73
74 @param immediately: whether to immediately invoke the poller, or
75 to wait until one period has passed
76 """
77 if self.running:
78 self.debug('already running')
79 else:
80 self.running = True
81 self._reschedule(immediately)
82
84 assert self._dc is None
85 if self.running:
86 if immediately:
87 self.run()
88 else:
89 self._dc = reactor.callLater(self.timeout, self.run)
90 else:
91 self.debug('shutting down, not rescheduling')
92
94 """Run the poller immediately, regardless of when it was last
95 run.
96 """
97
98 def reschedule(v):
99 self._reschedule()
100 return v
101
102 if self._dc and self._dc.active():
103
104
105 self._dc.cancel()
106 self._dc = None
107 d = maybeDeferred(self.proc)
108 d.addBoth(reschedule)
109
111 """Stop the poller.
112
113 This procedure ensures that the poller is stopped. It may be
114 called multiple times.
115 """
116 if self._dc:
117 self._dc.cancel()
118 self._dc = None
119 self.running = False
120