From 4be6e9a27ddace3e3e8dda470f29b60936c00519 Mon Sep 17 00:00:00 2001
From: Michael <heluecht@pirati.ca>
Date: Mon, 1 Aug 2022 05:56:55 +0000
Subject: [PATCH] Cache if an activity has recently been fetched

---
 src/Protocol/ActivityPub/Processor.php | 55 +++++++++++++++++++-------
 1 file changed, 41 insertions(+), 14 deletions(-)

diff --git a/src/Protocol/ActivityPub/Processor.php b/src/Protocol/ActivityPub/Processor.php
index 96308ca2cf..4a420490c3 100644
--- a/src/Protocol/ActivityPub/Processor.php
+++ b/src/Protocol/ActivityPub/Processor.php
@@ -58,6 +58,7 @@ use Friendica\Worker\Delivery;
 class Processor
 {
 	const CACHEKEY_FETCH_ACTIVITY = 'processor:fetchMissingActivity:';
+	const CACHEKEY_JUST_FETCHED   = 'processor:isJustFetched:';
 	/**
 	 * Extracts the tag character (#, @, !) from mention links
 	 *
@@ -305,27 +306,36 @@ class Processor
 		}
 
 		if (empty($activity['directmessage']) && ($activity['id'] != $activity['reply-to-id']) && !Post::exists(['uri' => $activity['reply-to-id']])) {
-			$recursion_depth = $activity['recursion-depth'] ?? 0;
-			Logger::notice('Parent not found. Try to refetch it.', ['parent' => $activity['reply-to-id'], 'recursion-depth' => $recursion_depth]);
-			if ($recursion_depth < DI::config()->get('system', 'max_recursion_depth')) {
-				$result = self::fetchMissingActivity($activity['reply-to-id'], $activity, '', Receiver::COMPLETION_AUTO);
-				if (empty($result) && self::isActivityGone($activity['reply-to-id'])) {
-					// Recursively delete this and all depending entries
-					if (!empty($activity['entry-id'])) {
-						Queue::deleteById($activity['entry-id']);
-					}
+			if (self::hasJustBeenFetched($activity['reply-to-id'])) {
+				Logger::notice('We just have tried to fetch this activity. We don\'t try it again.', ['parent' => $activity['reply-to-id']]);
+				$fetch_by_worker = false;
+				if (empty($conversation)) {
 					return [];
 				}
-				$fetch_by_worker = empty($result);
 			} else {
-				Logger::notice('Recursion level is too high.', ['parent' => $activity['reply-to-id'], 'recursion-depth' => $recursion_depth]);
-				$fetch_by_worker = true;
+				$recursion_depth = $activity['recursion-depth'] ?? 0;
+				Logger::notice('Parent not found. Try to refetch it.', ['parent' => $activity['reply-to-id'], 'recursion-depth' => $recursion_depth]);
+				if ($recursion_depth < DI::config()->get('system', 'max_recursion_depth')) {
+					$result = self::fetchMissingActivity($activity['reply-to-id'], $activity, '', Receiver::COMPLETION_AUTO);
+					$fetch_by_worker = empty($result);
+					if (empty($result) && self::isActivityGone($activity['reply-to-id'])) {
+						if (!empty($activity['entry-id'])) {
+							Queue::deleteById($activity['entry-id']);
+						}
+						if (empty($conversation)) {
+							return [];
+						}
+					}
+				} else {
+					Logger::notice('Recursion level is too high.', ['parent' => $activity['reply-to-id'], 'recursion-depth' => $recursion_depth]);
+					$fetch_by_worker = true;
+				}
 			}
 
 			if ($fetch_by_worker && Queue::hasWorker($activity)) {
 				Logger::notice('There is already a worker task to fetch the post.', ['id' => $activity['id'], 'parent' => $activity['reply-to-id']]);
 				$fetch_by_worker = false;
-				if (!empty($conversation)) {
+				if (empty($conversation)) {
 					return [];
 				}
 			}
@@ -335,7 +345,7 @@ class Processor
 				$activity['recursion-depth'] = 0;
 				$wid = Worker::add(PRIORITY_HIGH, 'FetchMissingActivity', $activity['reply-to-id'], $activity, '', Receiver::COMPLETION_AUTO);
 				Queue::setWorkerId($activity, $wid);
-				if (!empty($conversation)) {
+				if (empty($conversation)) {
 					return [];
 				}
 			} elseif (!empty($result)) {
@@ -466,6 +476,23 @@ class Processor
 		return $item;
 	}
 
+	/**
+	 * Check if a given activity has recently been fetched
+	 *
+	 * @param string $url
+	 * @return boolean
+	 */
+	private static function hasJustBeenFetched(string $url): bool
+	{
+		$cachekey = self::CACHEKEY_JUST_FETCHED . $url;
+		$time = DI::cache()->get($cachekey);
+		if (is_null($time)) {
+			DI::cache()->set($cachekey, time(), Duration::FIVE_MINUTES);
+			return false;
+		}
+		return ($time + 300) > time();
+	}
+
 	/**
 	 * Check if a given activity is no longer available
 	 *
-- 
2.39.5