Skip to content

Commit 8afcab0

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

File tree

6 files changed

+81
-26
lines changed

6 files changed

+81
-26
lines changed

apigee_edge.module

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1365,6 +1365,7 @@ function apigee_edge_user_presave(UserInterface $account) {
13651365
}
13661366
$developer = $result->getDeveloper();
13671367
$developer->save();
1368+
\Drupal::getContainer()->get('apigee_edge.dev_sync.last_update_tracker')->set($developer->getEmail(), \Drupal::time()->getCurrentTime());
13681369
}
13691370
catch (\Exception $exception) {
13701371
$previous = $exception->getPrevious();
@@ -1386,6 +1387,7 @@ function apigee_edge_user_presave(UserInterface $account) {
13861387
// "originalEmail" property's value on the entity.
13871388
$developer->enforceIsNew(TRUE);
13881389
$developer->save();
1390+
\Drupal::getContainer()->get('apigee_edge.dev_sync.last_update_tracker')->set($developer->getEmail(), \Drupal::time()->getCurrentTime());
13891391
}
13901392
catch (\Exception $exception) {
13911393
$context = [
@@ -1410,6 +1412,7 @@ function apigee_edge_user_presave(UserInterface $account) {
14101412
$developer->enforceIsNew(FALSE);
14111413
try {
14121414
$developer->save();
1415+
\Drupal::getContainer()->get('apigee_edge.dev_sync.last_update_tracker')->set($result->getDeveloper()->getEmail(), \Drupal::time()->getCurrentTime());
14131416
}
14141417
catch (ApiException $exception) {
14151418
$logger->error("Unable to update existing @developer developer's data after registered on the portal.", $context);

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: 57 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
/**
@@ -130,6 +139,30 @@ protected function executeRequest() {
130139
$this->edgeDevelopers = $this->loadDevelopers();
131140
}
132141

142+
/**
143+
* Schedules the update of a user.
144+
*
145+
* @param \Drupal\user\UserInterface $user
146+
* The user.
147+
*/
148+
protected function scheduleUserUpdate(UserInterface $user): void {
149+
$update_user_job = new UserUpdate($user->getEmail());
150+
$update_user_job->setTag($this->getTag());
151+
$this->scheduleJob($update_user_job);
152+
}
153+
154+
/**
155+
* Schedules the update of a developer.
156+
*
157+
* @param \Drupal\apigee_edge\Entity\DeveloperInterface $developer
158+
* The developer.
159+
*/
160+
protected function scheduleDeveloper(DeveloperInterface $developer): void {
161+
$update_developer_job = new DeveloperUpdate($developer->getEmail());
162+
$update_developer_job->setTag($this->getTag());
163+
$this->scheduleJob($update_developer_job);
164+
}
165+
133166
/**
134167
* {@inheritdoc}
135168
*/
@@ -144,20 +177,31 @@ public function execute(): bool {
144177
/** @var \Drupal\user\UserInterface $user */
145178
$user = $this->drupalUsers[$clean_email];
146179

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);
180+
$last_synced = $this->lastUpdateTracker->get($developer->getEmail(), 0);
181+
182+
if ($last_synced === 0) {
183+
$last_modified_delta = $developer->getLastModifiedAt()->getTimestamp() - $user->getChangedTime();
184+
if ($last_modified_delta === 0) {
185+
$this->lastUpdateTracker->set($developer->getEmail(), \Drupal::time()->getCurrentTime());
186+
continue;
187+
}
188+
189+
// Update Drupal user because the Apigee Edge developer is the most
190+
// recent.
191+
if ($last_modified_delta > 0) {
192+
$this->scheduleUserUpdate($user);
193+
}
194+
// Update Apigee Edge developer because the Drupal user is the most
195+
// recent.
196+
else {
197+
$this->scheduleDeveloper($developer);
198+
}
199+
}
200+
elseif ($last_synced < $developer->getLastModifiedAt()->getTimestamp()) {
201+
$this->scheduleUserUpdate($user);
154202
}
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);
203+
elseif ($last_synced < $user->getChangedTime()) {
204+
$this->scheduleDeveloper($developer);
161205
}
162206
}
163207

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)