@@ -32,21 +32,37 @@ final class Lock implements LockInterface, LoggerAwareInterface
32
32
private $ store ;
33
33
private $ key ;
34
34
private $ ttl ;
35
+ private $ autoRelease ;
36
+ private $ dirty = false ;
35
37
36
38
/**
37
- * @param Key $key
38
- * @param StoreInterface $store
39
- * @param float|null $ttl
39
+ * @param Key $key Resource to lock
40
+ * @param StoreInterface $store Store used to handle lock persistence
41
+ * @param float|null $ttl Maximum expected lock duration in seconds
42
+ * @param bool $autoRelease Whether to automatically release the lock or not when the lock instance is destroyed
40
43
*/
41
- public function __construct (Key $ key , StoreInterface $ store , $ ttl = null )
44
+ public function __construct (Key $ key , StoreInterface $ store , $ ttl = null , $ autoRelease = true )
42
45
{
43
46
$ this ->store = $ store ;
44
47
$ this ->key = $ key ;
45
48
$ this ->ttl = $ ttl ;
49
+ $ this ->autoRelease = (bool ) $ autoRelease ;
46
50
47
51
$ this ->logger = new NullLogger ();
48
52
}
49
53
54
+ /**
55
+ * Automatically releases the underlying lock when the object is destructed.
56
+ */
57
+ public function __destruct ()
58
+ {
59
+ if (!$ this ->autoRelease || !$ this ->dirty || !$ this ->isAcquired ()) {
60
+ return ;
61
+ }
62
+
63
+ $ this ->release ();
64
+ }
65
+
50
66
/**
51
67
* {@inheritdoc}
52
68
*/
@@ -59,6 +75,7 @@ public function acquire($blocking = false)
59
75
$ this ->store ->waitAndSave ($ this ->key );
60
76
}
61
77
78
+ $ this ->dirty = true ;
62
79
$ this ->logger ->info ('Successfully acquired the "{resource}" lock. ' , array ('resource ' => $ this ->key ));
63
80
64
81
if ($ this ->ttl ) {
@@ -71,6 +88,7 @@ public function acquire($blocking = false)
71
88
72
89
return true ;
73
90
} catch (LockConflictedException $ e ) {
91
+ $ this ->dirty = false ;
74
92
$ this ->logger ->warning ('Failed to acquire the "{resource}" lock. Someone else already acquired the lock. ' , array ('resource ' => $ this ->key ));
75
93
76
94
if ($ blocking ) {
@@ -96,13 +114,15 @@ public function refresh()
96
114
try {
97
115
$ this ->key ->resetLifetime ();
98
116
$ this ->store ->putOffExpiration ($ this ->key , $ this ->ttl );
117
+ $ this ->dirty = true ;
99
118
100
119
if ($ this ->key ->isExpired ()) {
101
120
throw new LockExpiredException (sprintf ('Failed to put off the expiration of the "%s" lock within the specified time. ' , $ this ->key ));
102
121
}
103
122
104
123
$ this ->logger ->info ('Expiration defined for "{resource}" lock for "{ttl}" seconds. ' , array ('resource ' => $ this ->key , 'ttl ' => $ this ->ttl ));
105
124
} catch (LockConflictedException $ e ) {
125
+ $ this ->dirty = false ;
106
126
$ this ->logger ->warning ('Failed to define an expiration for the "{resource}" lock, someone else acquired the lock. ' , array ('resource ' => $ this ->key ));
107
127
throw $ e ;
108
128
} catch (\Exception $ e ) {
@@ -116,7 +136,7 @@ public function refresh()
116
136
*/
117
137
public function isAcquired ()
118
138
{
119
- return $ this ->store ->exists ($ this ->key );
139
+ return $ this ->dirty = $ this -> store ->exists ($ this ->key );
120
140
}
121
141
122
142
/**
@@ -125,6 +145,7 @@ public function isAcquired()
125
145
public function release ()
126
146
{
127
147
$ this ->store ->delete ($ this ->key );
148
+ $ this ->dirty = false ;
128
149
129
150
if ($ this ->store ->exists ($ this ->key )) {
130
151
$ this ->logger ->warning ('Failed to release the "{resource}" lock. ' , array ('resource ' => $ this ->key ));
0 commit comments