def __init__(self): RMParserManager.instance = self self.parsers = {} self.forceParsersRun = False self.__maxFails = 100 self.__minDelayBetweenFails = 120 # 2 min self.__maxDelayBetweenFails = 300 # 5 min self.__stepDelayBetweenFails = 30 # 30 seconds self.__delayAfterMaxFails = 86400 # 1 day self.__lastRunningTimestamp = None # The timestamp when parsers last attempted to run self.__lastUpdateTimestamp = 0 # The timestamp when parsers actually ran self.__runningInterval = 60 # 1 minute self.parserTable = RMParserTable(globalDbManager.parserDatabase) self.parserDataTable = RMParserDataTable( globalDbManager.parserDatabase) self.forecastTable = RMForecastTable(globalDbManager.parserDatabase) self.userDataTypeTable = RMUserDataTypeTable( globalDbManager.parserDatabase) self.parserUserDataTypeTable = RMParserUserDataTable( globalDbManager.parserDatabase) self.userDataTypeTable.buildCache() self.mixer = None self.__load(os.path.dirname(__file__) + '/parsers')
def __init__(self): RMParserManager.instance = self self.parsers = {} self.forceParsersRun = False self.__maxFails = 100 self.__minDelayBetweenFails = 120 # 2 min self.__maxDelayBetweenFails = 300 # 5 min self.__stepDelayBetweenFails = 30 # 30 seconds self.__delayAfterMaxFails = 86400 # 1 day self.__lastRunningTimestamp = None # The timestamp when parsers last attempted to run self.__lastUpdateTimestamp = 0 # The timestamp when parsers actually ran self.__runningInterval = 60 # 1 minute self.parserTable = RMParserTable(globalDbManager.parserDatabase) self.parserDataTable = RMParserDataTable(globalDbManager.parserDatabase) self.forecastTable = RMForecastTable(globalDbManager.parserDatabase) self.userDataTypeTable = RMUserDataTypeTable(globalDbManager.parserDatabase) self.parserUserDataTypeTable = RMParserUserDataTable(globalDbManager.parserDatabase) self.userDataTypeTable.buildCache() self.mixer = None self.__load(os.path.dirname(__file__) + '/parsers')
class RMParserManager: IGNORE_PYC_MODULES = True instance = None def __init__(self): RMParserManager.instance = self self.parsers = {} self.forceParsersRun = False self.__maxFails = 100 self.__minDelayBetweenFails = 120 # 2 min self.__maxDelayBetweenFails = 300 # 5 min self.__stepDelayBetweenFails = 30 # 30 seconds self.__delayAfterMaxFails = 86400 # 1 day self.__lastRunningTimestamp = None # The timestamp when parsers last attempted to run self.__lastUpdateTimestamp = 0 # The timestamp when parsers actually ran self.__runningInterval = 60 # 1 minute self.parserTable = RMParserTable(globalDbManager.parserDatabase) self.parserDataTable = RMParserDataTable( globalDbManager.parserDatabase) self.forecastTable = RMForecastTable(globalDbManager.parserDatabase) self.userDataTypeTable = RMUserDataTypeTable( globalDbManager.parserDatabase) self.parserUserDataTypeTable = RMParserUserDataTable( globalDbManager.parserDatabase) self.userDataTypeTable.buildCache() self.mixer = None self.__load(os.path.dirname(__file__) + '/parsers') def preRun(self): unmixedForecastAvailable = False lastForecast = None latestForecastByParser = self.parserDataTable.getLastForecastByParser() for parserID in latestForecastByParser: parserConfig = self.findParserConfig(parserID) if parserConfig != None: parserConfig.runtimeLastForecastInfo = latestForecastByParser[ parserID] if not parserConfig.runtimeLastForecastInfo.processed: unmixedForecastAvailable = True if lastForecast == None: lastForecast = parserConfig.runtimeLastForecastInfo log.debug( "*** All values are already mixed! No need to run the Mixer!") for parserConfig in self.parsers: self.parserDataTable.clearHistory(parserConfig.dbID, False) globalDbManager.parserDatabase.commit() globalDbManager.parserDatabase.vacuum() return None, None def run(self, parserId=None, forceRunParser=False, forceRunMixer=False): currentTimestamp = rmCurrentTimestamp() forceRunParser = True if not forceRunParser and self.__lastRunningTimestamp is not None and ( currentTimestamp - self.__lastRunningTimestamp) < self.__runningInterval: # We want to run the parser only each N minutes. This condition is not met, try later. log.debug( "Parser %r not run lastRunning timestamp %s current %s" % (parserId, self.__lastRunningTimestamp, currentTimestamp)) return None, None self.__lastRunningTimestamp = currentTimestamp newValuesAvailable = False newForecast = RMForecastInfo(None, currentTimestamp) log.debug("*** BEGIN Running parsers: %d (%s)" % (newForecast.timestamp, rmTimestampToDateAsString(newForecast.timestamp))) for parserConfig in self.parsers: if parserId is not None and parserId != parserConfig.dbID: continue log.debug(" * Parser: %s -> %s" % (parserConfig, parserConfig.runtimeLastForecastInfo)) if parserConfig.enabled: if parserConfig.failCounter >= self.__maxFails: if forceRunParser or parserConfig.lastFailTimestamp is None or ( abs(newForecast.timestamp - parserConfig.lastFailTimestamp) >= self.__delayAfterMaxFails): parserConfig.failCounter = 0 parserConfig.lastFailTimestamp = None else: if parserConfig.failCounter == self.__maxFails: log.warning( " * Parser: %s - ignored because of lack of data (failCounter=%s, lastFail=%s)!" % (parserConfig, ` parserConfig.failCounter `, rmTimestampToDateAsString( parserConfig.lastFailTimestamp))) parserConfig.failCounter += 1 # Increment this to get rid of the above message. continue elif parserConfig.failCounter > 0: retryDelay = min( self.__minDelayBetweenFails + (parserConfig.failCounter - 1) * self.__stepDelayBetweenFails, self.__maxDelayBetweenFails) nextRetryTimestamp = parserConfig.lastFailTimestamp + retryDelay if newForecast.timestamp < nextRetryTimestamp: log.debug( " * Ignored because retry delay %d (sec) was not reached" % retryDelay) continue log.debug(" * Parser retry after previous fail") parser = self.parsers[parserConfig] lastUpdate = None if parserConfig.runtimeLastForecastInfo: # Check if parser hasn't run with an invalid future date if parserConfig.runtimeLastForecastInfo.timestamp <= currentTimestamp: lastUpdate = parserConfig.runtimeLastForecastInfo.timestamp # Save the newest parser run if lastUpdate is not None and lastUpdate > self.__lastUpdateTimestamp: self.__lastUpdateTimestamp = lastUpdate if not forceRunParser and not self.forceParsersRun and ( lastUpdate != None and (newForecast.timestamp - lastUpdate) < parser.parserInterval): log.debug( " * Ignored because interval %d not expired for timestamp %d lastUpdate: %d" % (parser.parserInterval, newForecast.timestamp, lastUpdate)) continue log.debug(" * Running parser %s with interval %d" % (parser.parserName, parser.parserInterval)) parser.settings = globalSettings.getSettings() parser.runtime[ RMParser.RuntimeDayTimestamp] = rmCurrentDayTimestamp() try: parser.lastKnownError = '' parser.isRunning = True parser.perform() parser.isRunning = False except Exception, e: log.error(" * Cannot execute parser %s" % parser.parserName) log.exception(e) parser.isRunning = False if len(parser.lastKnownError) == 0: parser.lastKnownError = 'Error: Failed to run' if not parser.hasValues(): parserConfig.failCounter += 1 parserConfig.lastFailTimestamp = newForecast.timestamp if len(parser.lastKnownError) == 0: parser.lastKnownError = 'Error: parser returned no values' parser.isRunning = False if parserConfig.failCounter == 1: log.warn(" * Parser %s returned no values" % parser.parserName) continue parserConfig.failCounter = 0 parserConfig.lastFailTimestamp = None if newForecast.id == None: self.forecastTable.addRecordEx(newForecast) parserConfig.runtimeLastForecastInfo = newForecast if not globalSettings.vibration: self.parserDataTable.removeEntriesWithParserIdAndTimestamp( parserConfig.dbID, parser.getValues()) self.parserDataTable.addRecords(newForecast.id, parserConfig.dbID, parser.getValues()) parser.clearValues() newValuesAvailable = True mixerDataValues = None if newValuesAvailable: globalDbManager.parserDatabase.vacuum() if not mixerDataValues is None: for parserConfig in self.parsers: if parserConfig.runtimeLastForecastInfo: parserConfig.runtimeLastForecastInfo.processed = True else: log.debug(" * No new value available from parsers") log.debug("*** END Running parsers: %s, %d (%s)" % ( ` newForecast.id `, newForecast.timestamp, rmTimestampToDateAsString(newForecast.timestamp))) return newForecast, mixerDataValues
class RMParserManager: IGNORE_PYC_MODULES = True instance = None def __init__(self): RMParserManager.instance = self self.parsers = {} self.forceParsersRun = False self.__maxFails = 100 self.__minDelayBetweenFails = 120 # 2 min self.__maxDelayBetweenFails = 300 # 5 min self.__stepDelayBetweenFails = 30 # 30 seconds self.__delayAfterMaxFails = 86400 # 1 day self.__lastRunningTimestamp = None # The timestamp when parsers last attempted to run self.__lastUpdateTimestamp = 0 # The timestamp when parsers actually ran self.__runningInterval = 60 # 1 minute self.parserTable = RMParserTable(globalDbManager.parserDatabase) self.parserDataTable = RMParserDataTable(globalDbManager.parserDatabase) self.forecastTable = RMForecastTable(globalDbManager.parserDatabase) self.userDataTypeTable = RMUserDataTypeTable(globalDbManager.parserDatabase) self.parserUserDataTypeTable = RMParserUserDataTable(globalDbManager.parserDatabase) self.userDataTypeTable.buildCache() self.mixer = None self.__load(os.path.dirname(__file__) + '/parsers') def preRun(self): unmixedForecastAvailable = False lastForecast = None latestForecastByParser = self.parserDataTable.getLastForecastByParser() for parserID in latestForecastByParser: parserConfig = self.findParserConfig(parserID) if parserConfig != None: parserConfig.runtimeLastForecastInfo = latestForecastByParser[parserID] if not parserConfig.runtimeLastForecastInfo.processed: unmixedForecastAvailable = True if lastForecast == None: lastForecast = parserConfig.runtimeLastForecastInfo log.debug("*** All values are already mixed! No need to run the Mixer!") for parserConfig in self.parsers: self.parserDataTable.clearHistory(parserConfig.dbID, False) globalDbManager.parserDatabase.commit() globalDbManager.parserDatabase.vacuum() return None, None def run(self, parserId = None, forceRunParser = False, forceRunMixer = False): currentTimestamp = rmCurrentTimestamp() forceRunParser = True if not forceRunParser and self.__lastRunningTimestamp is not None and (currentTimestamp - self.__lastRunningTimestamp) < self.__runningInterval: # We want to run the parser only each N minutes. This condition is not met, try later. log.debug("Parser %r not run lastRunning timestamp %s current %s" % (parserId, self.__lastRunningTimestamp, currentTimestamp)) return None, None self.__lastRunningTimestamp = currentTimestamp newValuesAvailable = False newForecast = RMForecastInfo(None, currentTimestamp) log.debug("*** BEGIN Running parsers: %d (%s)" % (newForecast.timestamp, rmTimestampToDateAsString(newForecast.timestamp))) for parserConfig in self.parsers: if parserId is not None and parserId != parserConfig.dbID: continue log.debug(" * Parser: %s -> %s" % (parserConfig, parserConfig.runtimeLastForecastInfo)) if parserConfig.enabled: if parserConfig.failCounter >= self.__maxFails: if forceRunParser or parserConfig.lastFailTimestamp is None or (abs(newForecast.timestamp - parserConfig.lastFailTimestamp) >= self.__delayAfterMaxFails): parserConfig.failCounter = 0 parserConfig.lastFailTimestamp = None else: if parserConfig.failCounter == self.__maxFails: log.warning(" * Parser: %s - ignored because of lack of data (failCounter=%s, lastFail=%s)!" % (parserConfig, `parserConfig.failCounter`, rmTimestampToDateAsString(parserConfig.lastFailTimestamp))) parserConfig.failCounter += 1 # Increment this to get rid of the above message. continue elif parserConfig.failCounter > 0: retryDelay = min(self.__minDelayBetweenFails + (parserConfig.failCounter - 1) * self.__stepDelayBetweenFails, self.__maxDelayBetweenFails) nextRetryTimestamp = parserConfig.lastFailTimestamp + retryDelay if newForecast.timestamp < nextRetryTimestamp: log.debug(" * Ignored because retry delay %d (sec) was not reached" % retryDelay) continue log.debug(" * Parser retry after previous fail") parser = self.parsers[parserConfig] lastUpdate = None if parserConfig.runtimeLastForecastInfo: # Check if parser hasn't run with an invalid future date if parserConfig.runtimeLastForecastInfo.timestamp <= currentTimestamp: lastUpdate = parserConfig.runtimeLastForecastInfo.timestamp # Save the newest parser run if lastUpdate is not None and lastUpdate > self.__lastUpdateTimestamp: self.__lastUpdateTimestamp = lastUpdate if not forceRunParser and not self.forceParsersRun and (lastUpdate != None and (newForecast.timestamp - lastUpdate) < parser.parserInterval): log.debug(" * Ignored because interval %d not expired for timestamp %d lastUpdate: %d" % (parser.parserInterval, newForecast.timestamp, lastUpdate)) continue log.debug(" * Running parser %s with interval %d" % (parser.parserName, parser.parserInterval)) parser.settings = globalSettings.getSettings() parser.runtime[RMParser.RuntimeDayTimestamp] = rmCurrentDayTimestamp() try: parser.lastKnownError = '' parser.isRunning = True parser.perform() parser.isRunning = False except Exception, e: log.error(" * Cannot execute parser %s" % parser.parserName) log.exception(e) parser.isRunning = False if len(parser.lastKnownError) == 0: parser.lastKnownError = 'Error: Failed to run' if not parser.hasValues(): parserConfig.failCounter += 1 parserConfig.lastFailTimestamp = newForecast.timestamp if len(parser.lastKnownError) == 0: parser.lastKnownError = 'Error: parser returned no values' parser.isRunning = False if parserConfig.failCounter == 1: log.warn (" * Parser %s returned no values" % parser.parserName) continue parserConfig.failCounter = 0 parserConfig.lastFailTimestamp = None if newForecast.id == None: self.forecastTable.addRecordEx(newForecast) parserConfig.runtimeLastForecastInfo = newForecast if not globalSettings.vibration: self.parserDataTable.removeEntriesWithParserIdAndTimestamp(parserConfig.dbID, parser.getValues()) self.parserDataTable.addRecords(newForecast.id, parserConfig.dbID, parser.getValues()) parser.clearValues() newValuesAvailable = True mixerDataValues = None if newValuesAvailable: globalDbManager.parserDatabase.vacuum() if not mixerDataValues is None: for parserConfig in self.parsers: if parserConfig.runtimeLastForecastInfo: parserConfig.runtimeLastForecastInfo.processed = True else: log.debug(" * No new value available from parsers") log.debug("*** END Running parsers: %s, %d (%s)" % (`newForecast.id`, newForecast.timestamp, rmTimestampToDateAsString(newForecast.timestamp))) return newForecast, mixerDataValues