diff --git a/database.sql b/database.sql index deaec5a24b..c7d37a4134 100644 --- a/database.sql +++ b/database.sql @@ -1,9 +1,23 @@ -- ------------------------------------------ --- Friendica 2019.09-dev (Dalmatian Bellflower) --- DB_UPDATE_VERSION 1319 +-- Friendica 2019.09-rc (Dalmatian Bellflower) +-- DB_UPDATE_VERSION 1321 -- ------------------------------------------ +-- +-- TABLE 2fa_app_specific_password +-- +CREATE TABLE IF NOT EXISTS `2fa_app_specific_password` ( + `id` mediumint unsigned NOT NULL auto_increment COMMENT 'Password ID for revocation', + `uid` mediumint unsigned NOT NULL COMMENT 'User ID', + `description` varchar(255) COMMENT 'Description of the usage of the password', + `hashed_password` varchar(255) NOT NULL COMMENT 'Hashed password', + `generated` datetime NOT NULL COMMENT 'Datetime the password was generated', + `last_used` datetime COMMENT 'Datetime the password was last used', + PRIMARY KEY(`id`), + INDEX `uid_description` (`uid`,`description`) +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Two-factor app-specific _password'; + -- -- TABLE 2fa_recovery_codes -- @@ -680,6 +694,7 @@ CREATE TABLE IF NOT EXISTS `item-delivery-data` ( `inform` mediumtext COMMENT 'Additional receivers of the linked item', `queue_count` mediumint NOT NULL DEFAULT 0 COMMENT 'Initial number of delivery recipients, used as item.delivery_queue_count', `queue_done` mediumint NOT NULL DEFAULT 0 COMMENT 'Number of successful deliveries, used as item.delivery_queue_done', + `queue_failed` mediumint NOT NULL DEFAULT 0 COMMENT 'Number of unsuccessful deliveries, used as item.delivery_queue_failed', `activitypub` mediumint NOT NULL DEFAULT 0 COMMENT 'Number of successful deliveries via ActivityPub', `dfrn` mediumint NOT NULL DEFAULT 0 COMMENT 'Number of successful deliveries via DFRN', `legacy_dfrn` mediumint NOT NULL DEFAULT 0 COMMENT 'Number of successful deliveries via legacy DFRN', diff --git a/src/Core/Worker.php b/src/Core/Worker.php index 037590c90d..3533f24e45 100644 --- a/src/Core/Worker.php +++ b/src/Core/Worker.php @@ -1222,11 +1222,12 @@ class Worker /** * Defers the current worker entry + * @return boolean had the entry been deferred? */ public static function defer() { if (empty(BaseObject::getApp()->queue)) { - return; + return false; } $queue = BaseObject::getApp()->queue; @@ -1241,7 +1242,7 @@ class Worker if ($new_retrial > $max_level) { Logger::info('The task exceeded the maximum retry count', ['id' => $id, 'max_level' => $max_level, 'retrial' => $new_retrial]); - return; + return false; } // Calculate the delay until the next trial @@ -1263,6 +1264,8 @@ class Worker DBA::update('workerqueue', $fields, ['id' => $id]); self::$db_duration += (microtime(true) - $stamp); self::$db_duration_write += (microtime(true) - $stamp); + + return true; } /** diff --git a/src/Model/Item.php b/src/Model/Item.php index 8ac88e96db..3a421e96c4 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -59,7 +59,7 @@ class Item extends BaseObject 'event-id', 'event-created', 'event-edited', 'event-start', 'event-finish', 'event-summary', 'event-desc', 'event-location', 'event-type', 'event-nofinish', 'event-adjust', 'event-ignore', 'event-id', - 'delivery_queue_count', 'delivery_queue_done' + 'delivery_queue_count', 'delivery_queue_done', 'delivery_queue_failed' ]; // Field list that is used to deliver items via the protocols diff --git a/src/Model/ItemDeliveryData.php b/src/Model/ItemDeliveryData.php index 1d5c37de2d..f007537f99 100644 --- a/src/Model/ItemDeliveryData.php +++ b/src/Model/ItemDeliveryData.php @@ -21,6 +21,7 @@ class ItemDeliveryData // New delivery fields with virtual field name in item fields 'queue_count' => 'delivery_queue_count', 'queue_done' => 'delivery_queue_done', + 'queue_failed' => 'delivery_queue_failed', ]; const ACTIVITYPUB = 1; @@ -88,6 +89,20 @@ class ItemDeliveryData return DBA::e('UPDATE `item-delivery-data` SET `queue_done` = `queue_done` + 1' . $sql . ' WHERE `iid` = ?', $item_id); } + /** + * Increments the queue_failed for the given item ID. + * + * Avoids racing condition between multiple delivery threads. + * + * @param integer $item_id + * @return bool + * @throws \Exception + */ + public static function incrementQueueFailed($item_id) + { + return DBA::e('UPDATE `item-delivery-data` SET `queue_failed` = `queue_failed` + 1 WHERE `iid` = ?', $item_id); + } + /** * Insert a new item delivery data entry * diff --git a/src/Object/Post.php b/src/Object/Post.php index 173b1e53af..7f9f84b546 100644 --- a/src/Object/Post.php +++ b/src/Object/Post.php @@ -432,7 +432,7 @@ class Post extends BaseObject 'return' => ($a->cmd) ? bin2hex($a->cmd) : '', 'delivery' => [ 'queue_count' => $item['delivery_queue_count'], - 'queue_done' => $item['delivery_queue_done'], + 'queue_done' => $item['delivery_queue_done'] + $item['delivery_queue_failed'], /// @todo Possibly display it separately in the future 'notifier_pending' => L10n::t('Notifier task is pending'), 'delivery_pending' => L10n::t('Delivery to remote servers is pending'), 'delivery_underway' => L10n::t('Delivery to remote servers is underway'), diff --git a/src/Worker/APDelivery.php b/src/Worker/APDelivery.php index 625ed5f2cb..3c12e45491 100644 --- a/src/Worker/APDelivery.php +++ b/src/Worker/APDelivery.php @@ -54,8 +54,8 @@ class APDelivery extends BaseObject } } - if (!$success) { - Worker::defer(); + if (!$success && !Worker::defer() && in_array($cmd, [Delivery::POST])) { + ItemDeliveryData::incrementQueueFailed($target_id); } } } diff --git a/src/Worker/Delivery.php b/src/Worker/Delivery.php index ab3e3a6e0b..7733d3f575 100644 --- a/src/Worker/Delivery.php +++ b/src/Worker/Delivery.php @@ -327,7 +327,9 @@ class Delivery extends BaseObject Model\Contact::markForArchival($contact); Logger::info('Delivery failed: defer message', ['id' => defaults($target_item, 'guid', $target_item['id'])]); - Worker::defer(); + if (!Worker::defer() && in_array($cmd, [Delivery::POST, Delivery::POKE])) { + Model\ItemDeliveryData::incrementQueueFailed($target_item['id']); + } } } @@ -412,7 +414,9 @@ class Delivery extends BaseObject if (empty($contact['contact-type']) || ($contact['contact-type'] != Model\Contact::TYPE_RELAY)) { Logger::info('Delivery failed: defer message', ['id' => defaults($target_item, 'guid', $target_item['id'])]); // defer message for redelivery - Worker::defer(); + if (!Worker::defer() && in_array($cmd, [Delivery::POST, Delivery::POKE])) { + Model\ItemDeliveryData::incrementQueueFailed($target_item['id'], Model\ItemDeliveryData::DIASPORA); + } } elseif (in_array($cmd, [Delivery::POST, Delivery::POKE])) { Model\ItemDeliveryData::incrementQueueDone($target_item['id'], Model\ItemDeliveryData::DIASPORA); } diff --git a/static/dbstructure.config.php b/static/dbstructure.config.php index aca6cf16b3..a00d957273 100755 --- a/static/dbstructure.config.php +++ b/static/dbstructure.config.php @@ -34,7 +34,7 @@ use Friendica\Database\DBA; if (!defined('DB_UPDATE_VERSION')) { - define('DB_UPDATE_VERSION', 1320); + define('DB_UPDATE_VERSION', 1321); } return [ @@ -763,6 +763,7 @@ return [ "inform" => ["type" => "mediumtext", "comment" => "Additional receivers of the linked item"], "queue_count" => ["type" => "mediumint", "not null" => "1", "default" => "0", "comment" => "Initial number of delivery recipients, used as item.delivery_queue_count"], "queue_done" => ["type" => "mediumint", "not null" => "1", "default" => "0", "comment" => "Number of successful deliveries, used as item.delivery_queue_done"], + "queue_failed" => ["type" => "mediumint", "not null" => "1", "default" => "0", "comment" => "Number of unsuccessful deliveries, used as item.delivery_queue_failed"], "activitypub" => ["type" => "mediumint", "not null" => "1", "default" => "0", "comment" => "Number of successful deliveries via ActivityPub"], "dfrn" => ["type" => "mediumint", "not null" => "1", "default" => "0", "comment" => "Number of successful deliveries via DFRN"], "legacy_dfrn" => ["type" => "mediumint", "not null" => "1", "default" => "0", "comment" => "Number of successful deliveries via legacy DFRN"],