summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'MLEB/Translate/src/Synchronization/GroupSynchronizationCache.php')
-rw-r--r--MLEB/Translate/src/Synchronization/GroupSynchronizationCache.php100
1 files changed, 90 insertions, 10 deletions
diff --git a/MLEB/Translate/src/Synchronization/GroupSynchronizationCache.php b/MLEB/Translate/src/Synchronization/GroupSynchronizationCache.php
index 64ea5ad0..d581ff69 100644
--- a/MLEB/Translate/src/Synchronization/GroupSynchronizationCache.php
+++ b/MLEB/Translate/src/Synchronization/GroupSynchronizationCache.php
@@ -35,18 +35,28 @@ class GroupSynchronizationCache {
/** @var PersistentCache */
private $cache;
/** @var int */
- private $timeoutSeconds;
+ private $initialTimeoutSeconds;
+ /** @var int */
+ private $incrementalTimeoutSeconds;
/** @var string Cache tag used for groups */
private const GROUP_LIST_TAG = 'gsc_%group_in_sync%';
/** @var string Cache tag used for tracking groups that have errors */
private const GROUP_ERROR_TAG = 'gsc_%group_with_error%';
+ /** @var string Cache tag used for tracking groups that are in review */
+ private const GROUP_IN_REVIEW_TAG = 'gsc_%group_in_review%';
+
+ // The timeout is set to 40 minutes initially, and then incremented by 10 minutes
+ // each time a message is marked as processed if group is about to expire.
+ public function __construct(
+ PersistentCache $cache,
+ int $initialTimeoutSeconds = 2400,
+ int $incrementalTimeoutSeconds = 600
- // TODO: Decide timeout based on monitoring. Also check if it needs to be configurable
- // based on the number of messages in the group.
- public function __construct( PersistentCache $cache, int $timeoutSeconds = 2400 ) {
+ ) {
$this->cache = $cache;
- $this->timeoutSeconds = $timeoutSeconds;
+ $this->initialTimeoutSeconds = $initialTimeoutSeconds;
+ $this->incrementalTimeoutSeconds = $incrementalTimeoutSeconds;
}
/**
@@ -66,7 +76,7 @@ class GroupSynchronizationCache {
/** Start synchronization process for a group and starts the expiry time */
public function markGroupForSync( string $groupId ): void {
- $expTime = $this->getExpireTime();
+ $expTime = $this->getExpireTime( $this->initialTimeoutSeconds );
$this->cache->set(
new PersistentCacheEntry(
$this->getGroupKey( $groupId ),
@@ -327,6 +337,12 @@ class GroupSynchronizationCache {
$this->cache->delete( $messageErrorKey );
}
+ /** Checks if the group has errors */
+ public function groupHasErrors( string $groupId ): bool {
+ $groupErrorKey = $this->getGroupErrorKey( $groupId );
+ return $this->cache->has( $groupErrorKey );
+ }
+
/** Checks if group has unresolved error messages. If not clears the group from error list */
public function syncGroupErrors( string $groupId ): GroupSynchronizationResponse {
$groupSyncResponse = $this->getGroupErrorInfo( $groupId );
@@ -341,14 +357,75 @@ class GroupSynchronizationCache {
return $groupSyncResponse;
}
+ public function markGroupAsInReview( string $groupId ): void {
+ $groupReviewKey = $this->getGroupReviewKey( $groupId );
+ $this->cache->set(
+ new PersistentCacheEntry(
+ $groupReviewKey,
+ $groupId,
+ null,
+ self::GROUP_IN_REVIEW_TAG
+ )
+ );
+ }
+
+ public function markGroupAsReviewed( string $groupId ): void {
+ $groupReviewKey = $this->getGroupReviewKey( $groupId );
+ $this->cache->delete( $groupReviewKey );
+ }
+
+ public function isGroupInReview( string $groupId ): bool {
+ return $this->cache->has( $this->getGroupReviewKey( $groupId ) );
+ }
+
+ public function extendGroupExpiryTime( string $groupId ): void {
+ $groupKey = $this->getGroupKey( $groupId );
+ $groupEntry = $this->cache->get( $groupKey );
+
+ if ( $groupEntry === [] ) {
+ // Group is currently not being processed.
+ throw new LogicException(
+ 'Requested extension of expiry time for a group that is not being processed. ' .
+ 'Check if group is being processed by calling isGroupBeingProcessed() first'
+ );
+ }
+
+ if ( $groupEntry[0]->hasExpired() ) {
+ throw new InvalidArgumentException(
+ 'Cannot extend expiry time for a group that has already expired.'
+ );
+ }
+
+ $newExpiryTime = $this->getExpireTime( $this->incrementalTimeoutSeconds );
+
+ // We start with the initial timeout minutes, we only change the timeout if the group
+ // is actually about to expire.
+ if ( $newExpiryTime < $groupEntry[0]->exptime() ) {
+ return;
+ }
+
+ $this->cache->setExpiry( $groupKey, $newExpiryTime );
+ }
+
+ /** @internal - Internal; For testing use only */
+ public function getGroupExpiryTime( $groupId ): int {
+ $groupKey = $this->getGroupKey( $groupId );
+ $groupEntry = $this->cache->get( $groupKey );
+ if ( $groupEntry === [] ) {
+ throw new InvalidArgumentException( "$groupId currently not in processing!" );
+ }
+
+ return $groupEntry[0]->exptime();
+ }
+
private function hasGroupTimedOut( int $syncExpTime ): bool {
return ( new DateTime() )->getTimestamp() > $syncExpTime;
}
- private function getExpireTime(): int {
+ private function getExpireTime( int $timeoutSeconds ): int {
$currentTime = ( new DateTime() )->getTimestamp();
$expTime = ( new DateTime() )
- ->setTimestamp( $currentTime + $this->timeoutSeconds )
+ ->setTimestamp( $currentTime + $timeoutSeconds )
->getTimestamp();
return $expTime;
@@ -404,6 +481,9 @@ class GroupSynchronizationCache {
private function getGroupMessageErrorTag( string $groupId ): string {
return "gsc_%error%_$groupId";
}
-}
-class_alias( GroupSynchronizationCache::class, '\MediaWiki\Extensions\Translate\GroupSynchronizationCache' );
+ private function getGroupReviewKey( string $groupId ): string {
+ $hash = substr( hash( 'sha256', $groupId ), 0, 40 );
+ return substr( "{$hash}_gsc_%review%_$groupId", 0, 255 );
+ }
+}