$this->_uit->runNextScheduledImport();
$all = $cc->search($filter);
$this->assertEquals($seq, $all->getFirstRecord()->seq);
-
- // setting manual timestamp to force run again
- $record->timestamp = $record->timestamp->subHour(1)->subSecond(1);
-
- $this->_uit->update($record);
-
+
+ $this->_runAgain($record);
+
$this->_uit->runNextScheduledImport();
$all = $cc->search($filter);
$this->assertEquals(7, $all->count());
}
/**
+ * make import run again
+ *
+ * @param Tinebase_Model_Import|array $record
+ */
+ protected function _runAgain($record)
+ {
+ if (! $record instanceof Tinebase_Model_Import) {
+ $record = new Tinebase_Model_Import($record);
+ }
+
+ // setting manual timestamp to force run again
+ $record->timestamp = $record->timestamp->subHour(1)->subSecond(1);
+ $this->_uit->update($record);
+ }
+
+ /**
* @see 0011342: ics-scheduled import only imports 1 remote calendar
*/
public function testMultipleScheduledImports()
$this->assertEquals(0, count($result), 'no imports should be found: ' . print_r($result->toArray(), true));
}
+
+ /**
+ * @see 0012082: deactivate failing scheduled imports
+ */
+ public function testDeactivatingImport()
+ {
+ // create invalid import
+ $import1 = $this->createScheduledImport();
+
+ // run 5 (maxfailcount) times
+ for ($i = 1; $i <= Tinebase_Controller_ScheduledImport::MAXFAILCOUNT; $i++) {
+ $importRun = $this->_uit->runNextScheduledImport();
+ $this->assertTrue(isset($importRun['failcount']), 'failcount should exist (import run ' . $i . ')');
+ $this->assertEquals($i, $importRun['failcount'], 'failcount should increase: ' . print_r($importRun, true));
+ $this->_runAgain($importRun);
+ }
+
+ // check if import is deactivated
+ $importRun = $this->_uit->runNextScheduledImport();
+ $this->assertTrue($importRun === null, 'import should not run: ' . print_r($importRun, true));
+ }
}
* @var Tinebase_Controller_ScheduledImport
*/
private static $instance = null;
+
+ const MAXFAILCOUNT = 5;
/**
* the constructor
return $this->_doScheduledImport($record)->toArray();
}
- return NULL;
+ return null;
}
+ /**
+ * @return Tinebase_Model_ImportFilter
+ */
public function getScheduledImportFilter()
{
$timestampBefore = null;
$aWeekAgo->subWeek(1);
$filter = new Tinebase_Model_ImportFilter(array(array(
+ array('field' => 'failcount', 'operator' => 'greater', 'value' => 5),
+ ),
+ array(
'condition' => 'OR', 'filters' => array(
array('field' => 'timestamp', 'operator' => 'isnull', 'value' => null),
array('condition' => 'AND', 'filters' => array(
*
* @param interval
* @param recursive
- * @return Object
+ * @return Tinebase_Model_Import|null
*/
protected function _getNextScheduledImport()
{
// Always sort by timestamp to ensure first in first out
$pagination = new Tinebase_Model_Pagination(array(
- 'limit' => 1,
+ 'limit' => 50,
'sort' => 'timestamp',
'dir' => 'ASC'
));
- $record = $this->search($filter, $pagination)->getFirstRecord();
-
- if (! $record) {
- if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
- Tinebase_Core::getLogger()->debug(__METHOD__ . ' ' . __LINE__ . ' No ScheduledImport could be found.');
- }
+ $records = $this->search($filter, $pagination);
- return NULL;
+ foreach ($records as $record) {
+ // TODO add failcount to filter in getScheduledImportFilter as
+ // no more valid imports are run if we have 50+ failing imports
+ if ($record->failcount < self::MAXFAILCOUNT) {
+ return $record;
+ } else {
+ if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) {
+ Tinebase_Core::getLogger()->info(__METHOD__ . ' ' . __LINE__ . ' Too many failures, skipping import');
+ }
+ }
}
- return $record;
+
+ if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) {
+ Tinebase_Core::getLogger()->debug(__METHOD__ . ' ' . __LINE__ . ' No valid ScheduledImport could be found.');
+ }
+
+ return null;
}
/**
try {
$importer = new $importer($options);
$importer->import($toImport);
+ $record->failcount = 0;
} catch (Exception $e) {
if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) {
Tinebase_Core::getLogger()->notice(__METHOD__ . ' ' . __LINE__
. ' Import failed.');
}
- // TODO log failure message in import record
Tinebase_Exception::log($e);
+
+ $record->lastfail = $e->getMessage();
+ $record->failcount = $record->failcount + 1;
}
if ($record->interval === Tinebase_Model_Import::INTERVAL_ONCE || !$record->timestamp instanceof Tinebase_DateTime) {
break;
}
- // update record
$record = $this->update($record);
} else {
'sourcetype' => array('presence' => 'required'),
'options' => array('allowEmpty' => true),
'source' => array('allowEmpty' => true),
+ 'failcount' => array('allowEmpty' => true, 'default' => 0),
+ 'lastfail' => array('allowEmpty' => true),
'created_by' => array('allowEmpty' => true),
'creation_time' => array('allowEmpty' => true),
'last_modified_by' => array('allowEmpty' => true),
{
/**
* update to 9.1
- *
+ *
* @see 0011178: allow to lock preferences for individual users
*/
public function update_0()
// delete index unique-fields
try {
$this->_backend->dropIndex('relations', 'unique-fields');
- } catch (Exception $e) {}
+ } catch (Exception $e) {
+ }
$declaration = new Setup_Backend_Schema_Index_Xml('
<index>
<name>unique-fields</name>
$this->createTable('path', $declaration);
$this->setApplicationVersion('Tinebase', '9.7');
}
+
+ /**
+ * update to 9.8
+ *
+ * adds failcount+lastfail to scheduled imports
+ *
+ * @see 0012082: deactivate failing scheduled imports
+ */
+ public function update_7()
+ {
+ if ($this->getTableVersion('import') < 2) {
+ $declaration = new Setup_Backend_Schema_Field_Xml('<field>
+ <name>failcount</name>
+ <type>integer</type>
+ </field>');
+ $this->_backend->addCol('import', $declaration);
+
+ $declaration = new Setup_Backend_Schema_Field_Xml('<field>
+ <name>lastfail</name>
+ <type>text</type>
+ </field>');
+ $this->_backend->addCol('import', $declaration);
+ }
+
+ $this->setTableVersion('import', '2');
+ $this->setApplicationVersion('Tinebase', '9.8');
+ }
}
<?xml version="1.0" encoding="utf-8"?>
<application>
<name>Tinebase</name>
- <version>9.7</version>
+ <version>9.8</version>
<tables>
<table>
<name>applications</name>
</table>
<table>
<name>import</name>
- <version>1</version>
+ <version>2</version>
<declaration>
<field>
<name>id</name>
<name>options</name>
<type>text</type>
</field>
+ <field>
+ <name>failcount</name>
+ <type>integer</type>
+ </field>
+ <field>
+ <name>lastfail</name>
+ <type>text</type>
+ </field>
<index>
<name>id</name>
<primary>true</primary>