diff --git a/app/Controllers/entryController.php b/app/Controllers/entryController.php index 57d403dc9..dd4efad39 100644 --- a/app/Controllers/entryController.php +++ b/app/Controllers/entryController.php @@ -268,6 +268,7 @@ class FreshRSS_entry_Controller extends FreshRSS_ActionController { } $databaseDAO = FreshRSS_Factory::createDatabaseDAO(); + $databaseDAO->minorDbMaintenance(); $databaseDAO->optimize(); $feedDAO = FreshRSS_Factory::createFeedDao(); @@ -295,6 +296,9 @@ class FreshRSS_entry_Controller extends FreshRSS_ActionController { @set_time_limit(300); } + $databaseDAO = FreshRSS_Factory::createDatabaseDAO(); + $databaseDAO->minorDbMaintenance(); + $feedDAO = FreshRSS_Factory::createFeedDao(); $feeds = $feedDAO->listFeeds(); $nb_total = 0; @@ -310,9 +314,6 @@ class FreshRSS_entry_Controller extends FreshRSS_ActionController { $feedDAO->updateCachedValues(); $feedDAO->commit(); - $databaseDAO = FreshRSS_Factory::createDatabaseDAO(); - $databaseDAO->minorDbMaintenance(); - invalidateHttpCache(); Minz_Request::good( _t('feedback.sub.purge_completed', $nb_total), diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 234eb7635..efdaea7f3 100644 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -567,7 +567,7 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController { $mtime = $feed->cacheModifiedTime() ?: time(); } catch (FreshRSS_Feed_Exception $e) { Minz_Log::warning($e->getMessage()); - $feedDAO->updateLastUpdate($feed->id(), true); + $feedDAO->updateLastError($feed->id()); if ($e->getCode() === 410) { // HTTP 410 Gone Minz_Log::warning('Muting gone feed: ' . $feed->url(false)); @@ -720,10 +720,13 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController { } } - $feedDAO->updateLastUpdate($feed->id(), false, $mtime); - if ($simplePiePush === null) { + if ($simplePiePush === null) { // Not WebSub + $feedDAO->updateLastUpdate($feed->id(), $mtime); // Do not call for WebSub events, as we do not know the list of articles still on the upstream feed. $needFeedCacheRefresh |= ($feed->markAsReadUponGone($feedIsEmpty, $mtime) != false); + } elseif ($feed->inError()) { + // Reset feed error state in case of successful WebSub push + $feedDAO->updateLastError($feed->id(), 0); } if ($needFeedCacheRefresh) { $feedsCacheToRefresh[] = $feed; @@ -928,12 +931,13 @@ class FreshRSS_feed_Controller extends FreshRSS_ActionController { $feedDAO = FreshRSS_Factory::createFeedDao(); $feedDAO->updateCachedValues(); } else { - if ($id === 0 && $url === '') { - // Case of a batch refresh (e.g. cron) + if (!$noCommit) { $databaseDAO = FreshRSS_Factory::createDatabaseDAO(); $databaseDAO->minorDbMaintenance(); Minz_ExtensionManager::callHookVoid(Minz_HookType::FreshrssUserMaintenance); - + } + if ($id === 0 && $url === '') { + // Case of a batch refresh (e.g. cron) FreshRSS_feed_Controller::commitNewEntries(); $feedDAO = FreshRSS_Factory::createFeedDao(); $feedDAO->updateCachedValues(); diff --git a/app/Models/Category.php b/app/Models/Category.php index 08ab22c19..297dfe53f 100644 --- a/app/Models/Category.php +++ b/app/Models/Category.php @@ -267,7 +267,11 @@ class FreshRSS_Category extends Minz_Model { } $catDAO = FreshRSS_Factory::createCategoryDao(); - $catDAO->updateLastUpdate($this->id(), !$ok); + if ($ok) { + $catDAO->updateLastUpdate($this->id()); + } else { + $catDAO->updateLastError($this->id()); + } return (bool)$ok; } diff --git a/app/Models/CategoryDAO.php b/app/Models/CategoryDAO.php index 82152c54d..a38657505 100644 --- a/app/Models/CategoryDAO.php +++ b/app/Models/CategoryDAO.php @@ -30,7 +30,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { } elseif ($name === 'lastUpdate') { //v1.20.0 return $this->pdo->exec('ALTER TABLE `_category` ADD COLUMN `lastUpdate` BIGINT DEFAULT 0') !== false; } elseif ($name === 'error') { //v1.20.0 - return $this->pdo->exec('ALTER TABLE `_category` ADD COLUMN error SMALLINT DEFAULT 0') !== false; + return $this->pdo->exec('ALTER TABLE `_category` ADD COLUMN error BIGINT DEFAULT 0') !== false; } elseif ('attributes' === $name) { //v1.15.0 $ok = $this->pdo->exec('ALTER TABLE `_category` ADD COLUMN attributes TEXT') !== false; @@ -212,14 +212,30 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { } } - public function updateLastUpdate(int $id, bool $inError = false, int $mtime = 0): int|false { + public function updateLastUpdate(int $id, int $mtime = 0): int|false { $sql = <<<'SQL' - UPDATE `_category` SET `lastUpdate`=:last_update, error=:error WHERE id=:id + UPDATE `_category` SET `lastUpdate`=:last_update, error=0 WHERE id=:id SQL; $stm = $this->pdo->prepare($sql); if ($stm !== false && $stm->bindValue(':last_update', $mtime <= 0 ? time() : $mtime, PDO::PARAM_INT) && - $stm->bindValue(':error', $inError ? 1 : 0, PDO::PARAM_INT) && + $stm->bindValue(':id', $id, PDO::PARAM_INT) && + $stm->execute()) { + return $stm->rowCount(); + } else { + $info = $stm === false ? $this->pdo->errorInfo() : $stm->errorInfo(); + Minz_Log::error('SQL error ' . __METHOD__ . json_encode($info)); + return false; + } + } + + public function updateLastError(int $id, ?int $mtime = null): int|false { + $sql = <<<'SQL' + UPDATE `_category` SET error=:last_update WHERE id=:id + SQL; + $stm = $this->pdo->prepare($sql); + if ($stm !== false && + $stm->bindValue(':last_update', $mtime === null || $mtime < 0 ? time() : $mtime, PDO::PARAM_INT) && $stm->bindValue(':id', $id, PDO::PARAM_INT) && $stm->execute()) { return $stm->rowCount(); diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index fbc74dd24..096d7e6e0 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -1951,7 +1951,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { public function updateLastSeenUnchanged(int $id_feed, int $mtime = 0): int|false { $sql = <<<'SQL' UPDATE `_entry` SET `lastSeen` = :mtime - WHERE id_feed = :id_feed1 AND `lastSeen` = ( + WHERE id_feed = :id_feed1 AND `lastSeen` >= ( SELECT `lastUpdate` FROM `_feed` f WHERE f.id = :id_feed2 ) diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php index 9130c5e7c..9e49670d0 100644 --- a/app/Models/FeedDAO.php +++ b/app/Models/FeedDAO.php @@ -227,14 +227,30 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { /** * @see updateCachedValues() */ - public function updateLastUpdate(int $id, bool $inError = false, int $mtime = 0): int|false { + public function updateLastUpdate(int $id, int $mtime = 0): int|false { $sql = <<<'SQL' - UPDATE `_feed` SET `lastUpdate`=:last_update, error=:error WHERE id=:id + UPDATE `_feed` SET `lastUpdate`=:last_update, error=0 WHERE id=:id SQL; $stm = $this->pdo->prepare($sql); if ($stm !== false && $stm->bindValue(':last_update', $mtime <= 0 ? time() : $mtime, PDO::PARAM_INT) && - $stm->bindValue(':error', $inError ? 1 : 0, PDO::PARAM_INT) && + $stm->bindValue(':id', $id, PDO::PARAM_INT) && + $stm->execute()) { + return $stm->rowCount(); + } else { + $info = $stm === false ? $this->pdo->errorInfo() : $stm->errorInfo(); + Minz_Log::warning(__METHOD__ . ' error: ' . $sql . ' : ' . json_encode($info)); + return false; + } + } + + public function updateLastError(int $id, ?int $mtime = null): int|false { + $sql = <<<'SQL' + UPDATE `_feed` SET error=:last_update WHERE id=:id + SQL; + $stm = $this->pdo->prepare($sql); + if ($stm !== false && + $stm->bindValue(':last_update', $mtime === null || $mtime < 0 ? time() : $mtime, PDO::PARAM_INT) && $stm->bindValue(':id', $id, PDO::PARAM_INT) && $stm->execute()) { return $stm->rowCount(); @@ -445,6 +461,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { public function listFeedsOrderUpdate(int $defaultCacheDuration = 3600, int $limit = 0): array { $ttlDefault = FreshRSS_Feed::TTL_DEFAULT; $refreshThreshold = time() + 60; + $lastAttemptExpression = '(CASE WHEN error > `lastUpdate` THEN error ELSE `lastUpdate` END)'; $sql = <<= 0) { $sql .= "\n" . <<= {$ttlDefault} - AND `lastUpdate` < ({$refreshThreshold}-(CASE WHEN ttl={$ttlDefault} THEN {$defaultCacheDuration} ELSE ttl END)) + AND {$lastAttemptExpression} < ({$refreshThreshold}-(CASE WHEN ttl={$ttlDefault} THEN {$defaultCacheDuration} ELSE ttl END)) SQL; } $sql .= "\n" . << 0) { $sql .= "\n" . <<