Skip to content

Commit 3bf3d29

Browse files
committed
Store last update attempts locally
for all developer/users
1 parent f7f1e81 commit 3bf3d29

File tree

5 files changed

+66
-26
lines changed

5 files changed

+66
-26
lines changed

apigee_edge.services.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,3 +217,8 @@ services:
217217
apigee_edge.post_user_delete_action_performer:
218218
class: Drupal\apigee_edge\User\RemoveRelatedDeveloperAccountSynchronousPostUserDeleteActionPerformer
219219
arguments: ['@entity_type.manager', '@logger.channel.apigee_edge']
220+
221+
apigee_edge.dev_sync.last_update_tracker:
222+
class: Drupal\Core\KeyValueStore\KeyValueStoreInterface
223+
factory: [ '@keyvalue', 'get' ]
224+
arguments: [ 'apigee_edge.dev_sync.last_update_tracker' ]

src/Job/DeveloperCreateUpdate.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ protected function executeRequest() {
7070
if ($result->getSuccessfullyAppliedChanges() > 0) {
7171
$result->getDeveloper()->save();
7272
}
73+
// Record the sync attempt timestamp for the developer's email,
74+
// regardless of whether an entity update occurred, to prevent redundant
75+
// sync operations. This ensures that the developer will only be re-synced
76+
// if a new relevant change is detected after this timestamp.
77+
\Drupal::getContainer()->get('apigee_edge.dev_sync.last_update_tracker')->set($result->getDeveloper()->getEmail(), \Drupal::time()->getCurrentTime());
7378
}
7479
catch (\Exception $exception) {
7580
$message = '@operation: Skipping %mail developer. @message %function (line %line of %file). <pre>@backtrace_string</pre>';

src/Job/DeveloperSync.php

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@
2020
namespace Drupal\apigee_edge\Job;
2121

2222
use Drupal\apigee_edge\Entity\Developer;
23+
use Drupal\apigee_edge\Entity\DeveloperInterface;
24+
use Drupal\Core\KeyValueStore\KeyValueStoreInterface;
2325
use Drupal\user\Entity\User;
26+
use Drupal\user\UserInterface;
2427

2528
/**
2629
* A job that synchronizes Apigee Edge developers and Drupal users.
@@ -58,6 +61,11 @@ class DeveloperSync extends EdgeJob {
5861
*/
5962
protected $filter = NULL;
6063

64+
/**
65+
* KV store tracks last update attempts for each user/developer.
66+
*/
67+
protected KeyValueStoreInterface $lastUpdateTracker;
68+
6169
/**
6270
* DeveloperSync constructor.
6371
*
@@ -67,6 +75,7 @@ class DeveloperSync extends EdgeJob {
6775
public function __construct(?string $filter) {
6876
parent::__construct();
6977
$this->filter = $filter;
78+
$this->lastUpdateTracker = \Drupal::service('apigee_edge.dev_sync.last_update_tracker');
7079
}
7180

7281
/**
@@ -136,6 +145,18 @@ protected function executeRequest() {
136145
public function execute(): bool {
137146
parent::execute();
138147

148+
$update_drupal_user = function (UserInterface $user) {
149+
$update_user_job = new UserUpdate($user->getEmail());
150+
$update_user_job->setTag($this->getTag());
151+
$this->scheduleJob($update_user_job);
152+
};
153+
154+
$update_developer = function (DeveloperInterface $developer) {
155+
$update_developer_job = new DeveloperUpdate($developer->getEmail());
156+
$update_developer_job->setTag($this->getTag());
157+
$this->scheduleJob($update_developer_job);
158+
};
159+
139160
// Update Apigee Edge developers and Drupal users if needed.
140161
$identical_entities = array_intersect_key($this->edgeDevelopers, $this->drupalUsers);
141162
foreach ($identical_entities as $clean_email => $entity) {
@@ -144,20 +165,31 @@ public function execute(): bool {
144165
/** @var \Drupal\user\UserInterface $user */
145166
$user = $this->drupalUsers[$clean_email];
146167

147-
$last_modified_delta = $developer->getLastModifiedAt()->getTimestamp() - $user->getChangedTime();
148-
// Update Drupal user because the Apigee Edge developer is the most
149-
// recent.
150-
if ($last_modified_delta > 0) {
151-
$update_user_job = new UserUpdate($user->getEmail());
152-
$update_user_job->setTag($this->getTag());
153-
$this->scheduleJob($update_user_job);
168+
$last_synced = $this->lastUpdateTracker->get($developer->getEmail(), 0);
169+
170+
if ($last_synced === 0) {
171+
$last_modified_delta = $developer->getLastModifiedAt()->getTimestamp() - $user->getChangedTime();
172+
if ($last_modified_delta === 0) {
173+
$this->lastUpdateTracker->set($developer->getEmail(), \Drupal::time()->getCurrentTime());
174+
continue;
175+
}
176+
177+
// Update Drupal user because the Apigee Edge developer is the most
178+
// recent.
179+
if ($last_modified_delta > 0) {
180+
$update_drupal_user($user);
181+
}
182+
// Update Apigee Edge developer because the Drupal user is the most
183+
// recent.
184+
else {
185+
$update_developer($developer);
186+
}
187+
}
188+
elseif ($last_synced < $developer->getLastModifiedAt()->getTimestamp()) {
189+
$update_drupal_user($user);
154190
}
155-
// Update Apigee Edge developer because the Drupal user is the most
156-
// recent.
157-
elseif ($last_modified_delta < 0) {
158-
$update_developer_job = new DeveloperUpdate($developer->getEmail());
159-
$update_developer_job->setTag($this->getTag());
160-
$this->scheduleJob($update_developer_job);
191+
elseif ($last_synced < $user->getChangedTime()) {
192+
$update_developer($developer);
161193
}
162194
}
163195

src/Job/UserCreateUpdate.php

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -75,14 +75,14 @@ protected function executeRequest() {
7575
// the same developer in apigee_edge_user_presave() while creating
7676
// Drupal user based on a developer should be avoided.
7777
_apigee_edge_set_sync_in_progress(TRUE);
78-
79-
// Synchronize user's last modified timestamp with developer's timestamp
80-
// to maintain data consistency and prevent infinite sync loops where
81-
// outdated timestamps cause repeated scheduling of sync operations.
82-
// @see \Drupal\apigee_edge\Job\DeveloperSync::execute()
83-
$result->getUser()->setChangedTime($developer->getLastModifiedAt()->getTimestamp());
8478
$result->getUser()->save();
8579
}
80+
81+
// Record the sync attempt timestamp for the developer's email,
82+
// regardless of whether an entity update occurred, to prevent redundant
83+
// sync operations. This ensures that the developer will only be re-synced
84+
// if a new relevant change is detected after this timestamp.
85+
\Drupal::getContainer()->get('apigee_edge.dev_sync.last_update_tracker')->set($developer->getEmail(), \Drupal::time()->getCurrentTime());
8686
}
8787
catch (\Exception $exception) {
8888
$message = '@operation: Skipping %mail user. @message %function (line %line of %file). <pre>@backtrace_string</pre>';
@@ -91,8 +91,8 @@ protected function executeRequest() {
9191
'@operation' => get_class($this),
9292
];
9393
$context += Error::decodeException($exception);
94-
// Unset backtrace, exception, severity_level as they are not shown in the log message
95-
// and throws php warning in logs.
94+
// Unset backtrace, exception, severity_level as they are not shown in
95+
// the log message and throws php warning in logs.
9696
unset($context['backtrace'], $context['exception'], $context['severity_level']);
9797

9898
$this->logger()->error($message, $context);
@@ -127,6 +127,9 @@ protected function beforeUserSave(DeveloperToUserConversionResult $result) : voi
127127
throw $problem;
128128
}
129129
}
130+
// It's necessary because changed time is automatically updated on the
131+
// UI only.
132+
$result->getUser()->setChangedTime(\Drupal::time()->getCurrentTime());
130133
}
131134

132135
/**

src/UserDeveloperConverter.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -182,11 +182,6 @@ public function convertDeveloper(DeveloperInterface $developer) : DeveloperToUse
182182
$user = $user_storage->create([
183183
'pass' => \Drupal::service('password_generator')->generate(),
184184
]);
185-
// Set user creation date to match the original developer's creation
186-
// timestamp to maintain chronological consistency between related
187-
// entities and prevent confusion when comparing created vs modified dates
188-
// in the user interface.
189-
$user->set('created', $developer->getCreatedAt()->getTimestamp());
190185
// Suppress invalid email validation errors.
191186
DeveloperEmailUniqueValidator::whitelist($developer->id());
192187
}

0 commit comments

Comments
 (0)