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