Package flumotion :: Package common :: Module poller
[hide private]

Source Code for Module flumotion.common.poller

  1  # -*- Mode: Python; test-case-name: flumotion.test.test_common -*- 
  2  # vi:si:et:sw=4:sts=4:ts=4 
  3   
  4  # Flumotion - a streaming media server 
  5  # Copyright (C) 2004,2005,2006,2007,2008,2009 Fluendo, S.L. 
  6  # Copyright (C) 2010,2011 Flumotion Services, S.A. 
  7  # All rights reserved. 
  8  # 
  9  # This file may be distributed and/or modified under the terms of 
 10  # the GNU Lesser General Public License version 2.1 as published by 
 11  # the Free Software Foundation. 
 12  # This file is distributed without any warranty; without even the implied 
 13  # warranty of merchantability or fitness for a particular purpose. 
 14  # See "LICENSE.LGPL" in the source distribution for more information. 
 15  # 
 16  # Headers in this file shall remain intact. 
 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
79 - def _reschedule(self, immediately=False):
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
89 - def run(self):
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 # we don't get here in the normal periodic case, only for 100 # explicit run() invocations 101 self._dc.cancel() 102 self._dc = None 103 d = maybeDeferred(self.proc) 104 d.addBoth(reschedule)
105
106 - def stop(self):
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