-
-
Notifications
You must be signed in to change notification settings - Fork 9.8k
[Lock] Check TTL expiration in lock acquisition #22542
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
7bd2873 to
3b0db33
Compare
|
Can this wait 3.4? We'd like to close 3.3 asap :) |
|
From the 3 pending PR related to the components Lock, this one is the most important. It avoid to acquire an expired Lock (due to network latency for instance). Cf discussion in the issue. That's said, with an adequate warning in the documentation, this PR is not an absolute requirement. |
|
PR rebased and fixed add messages in Exceptions. |
|
|
||
| public function testAbortAfterExpiration() | ||
| { | ||
| $this->markTestIncomplete('Memcached expecte a TTL greater than 1 sec. Simulating slow network is too complex'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be marked as skipped not incomplete.
|
What's the status of this PR? I'd like to merge/close all PRs about the lock component ASAP to avoid having to revert the component for 3.4. |
|
@fabpot waiting for approvals. As saids in #22542 (comment) this PR is the most important IMO related to lock component. |
| try { | ||
| $store->putOffExpiration($key, $ttl); | ||
| if (0.0 >= $adjustedTtl = $expireAt - microtime(true)) { | ||
| $this->logger->warning('TTL expires during the put off the expiration of the "{resource}" lock.', array('resource' => $key, 'store' => $store, 'ttl' => $ttl)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Message is not clear to me. Can you explain what you are trying to say?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are trying to put off the expiration of the lock (to extend it life duration) but the method take more time to perform that task than the asked TTL.
For instance, when calling putOffExpiration($key, 31) takes 31 seconds.
| } | ||
|
|
||
| if (microtime(true) >= $expireAt) { | ||
| throw new LockExpiredException(sprintf('Failed to put of the expiration the "%s" lock in less than "%f".', $key, $ttl)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If put off is the right verb, then there is a typo here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing of after expiration also
| return; | ||
| $expireAt = microtime(true) + $this->initialTtl; | ||
| if (!$this->memcached->add((string) $key, $token, (int) ceil($this->initialTtl))) { | ||
| // the lock is already acquire. It could be us. Let's try to put off. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
acquired.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
| // the lock is already acquire. It could be us. Let's try to put off. | ||
| $this->putOffExpiration($key, $this->initialTtl); | ||
| if (microtime(true) >= $expireAt) { | ||
| throw new LockExpiredException(sprintf('Failed to store the "%s" lock in less than "%f".', $key, $this->initialTtl)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would remove in less than. I would also add the unit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed (same for others usage)
| } | ||
|
|
||
| if (microtime(true) >= $expireAt) { | ||
| throw new LockExpiredException(sprintf('Failed to put of the expiration the "%s" lock in less than "%f".', $key, $ttl)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
put off?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
| } | ||
|
|
||
| if (microtime(true) >= $expireAt) { | ||
| throw new LockExpiredException(sprintf('Failed to put of the expiration the "%s" lock in less than "%f".', $key, $ttl)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same
|
|
||
| public function testAbortAfterExpiration() | ||
| { | ||
| $this->markTestSkipped('Memcached expecte a TTL greater than 1 sec. Simulating slow network is too complex'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo expects
Simulating a slow network is too hard
76587d0 to
0bd266a
Compare
54e28aa to
aa6c353
Compare
|
PR rebased with few changes
|
aa6c353 to
1522312
Compare
chalasr
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
with minor comment
|
|
||
| public function testAbortAfterExpiration() | ||
| { | ||
| $this->markTestSkipped('Memcached expecte a TTL greater than 1 sec. Simulating a slow network is too hard'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo expects
a7bc204 to
2cd518e
Compare
81162a6 to
2e4f434
Compare
2e4f434 to
9743bfb
Compare
|
failling test not related to this PR |
| $newExpiringDate = \DateTimeImmutable::createFromFormat('U.u', (string) (microtime(true) + $ttl)); | ||
| $newTime = microtime(true) + $ttl; | ||
|
|
||
| if (null === $this->expiringDate || $newExpiringDate < $this->expiringDate) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Switch to float comparison instead of datetime, due to bug in PHP => https://3v4l.org/bSt3d
src/Symfony/Component/Lock/Key.php
Outdated
| } | ||
| } | ||
|
|
||
| public function resetExpiringDate() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be resetExpiringTime() now, right?
src/Symfony/Component/Lock/Key.php
Outdated
| /** | ||
| * @return \DateTimeImmutable | ||
| */ | ||
| public function getExpiringDate() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using microtime is a internal implementation to fix issue with \Datetime comparison. IMHO there is no reason to change the public interface of this class, returning a \Datetime here is more usefull than returning a microtime.
If I have to change it, I would rather stop using ExpiringThing and replace them by lifetime with resetLifetime(), reduceLifetime(float $ttl), isExpired(): bool and getTimeToLive(): float WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We now have a public method that takes a float and the rest of the API dealing with DateTime, that feels slightly inconsistent to me as well. I'm fine with float only.
Would getTimeToLive() return the remaining ttl at the moment? Or just the original (full) ttl?
Do we really need it? (just wondering)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getTimeToLive should returns the raimaining TTL. Returning the initial TTL without knowing when this TTL had been sets is useless.
The purpose is to let the locker knowing if he has time to perform his job.
For instance you iterate over thousands of items. You know that it takes between 1 and 3 seconds to treat 1 item. You can use the the getTimeToLive after each item and when the TTL is below 5 seconds you call the refresh() method to extends the life of your lock.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good to me
1d60277 to
3b6be16
Compare
| public function getRemainingLifetime() | ||
| { | ||
| $this->expiringDate = null; | ||
| return null === $this->expiringTime ? null : $this->expiringTime - microtime(true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should it be null or (float) PHP_MAX_INT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd keep null with a comment explaining its meaning in the return annotation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
3b6be16 to
cb7b16c
Compare
cb7b16c to
b9de71b
Compare
|
👍 |
|
Thank you @jderusse. |
…sse) This PR was squashed before being merged into the 3.4 branch (closes #22542). Discussion ---------- [Lock] Check TTL expiration in lock acquisition | Q | A | ------------- | --- | Branch? | 3.4 | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | #22452 | License | MIT | Doc PR | NA This PR improve lock acquisition by throwing exception when the TTL is expired during the lock process. Commits ------- f74ef35 [Lock] Check TTL expiration in lock acquisition
This PR improve lock acquisition by throwing exception when the TTL is expired during the lock process.