@@ -111,6 +111,8 @@ impl Lock for PostgresLock {
111111 . context ( "Failed to acquire connection for shared lock" ) ?;
112112
113113 // Acquire shared advisory lock (returns void, so we use query instead of query_scalar)
114+ // PostgreSQL advisory locks are session-scoped and automatically released when the
115+ // connection is closed or returned to the pool.
114116 sqlx:: query ( "SELECT pg_advisory_lock_shared($1)" )
115117 . bind ( self . key_hash )
116118 . execute ( & mut * conn)
@@ -119,6 +121,10 @@ impl Lock for PostgresLock {
119121
120122 debug ! ( "Acquired shared lock for key: {}" , self . key) ;
121123
124+ // Return a guard that holds the connection. When the guard is dropped, the
125+ // connection is automatically returned to the pool, which triggers the lock release.
126+ // This design is safe and reliable - it leverages PostgreSQL's guarantee that
127+ // locks are released when a connection closes, without needing explicit unlock calls.
122128 Ok ( Box :: new ( PostgresSharedLockGuard {
123129 key : self . key . clone ( ) ,
124130 _conn : conn,
@@ -136,6 +142,8 @@ impl Lock for PostgresLock {
136142 . context ( "Failed to acquire connection for exclusive lock" ) ?;
137143
138144 // Acquire exclusive advisory lock (returns void, so we use query instead of query_scalar)
145+ // PostgreSQL advisory locks are session-scoped and automatically released when the
146+ // connection is closed or returned to the pool.
139147 sqlx:: query ( "SELECT pg_advisory_lock($1)" )
140148 . bind ( self . key_hash )
141149 . execute ( & mut * conn)
@@ -144,13 +152,35 @@ impl Lock for PostgresLock {
144152
145153 debug ! ( "Acquired exclusive lock for key: {}" , self . key) ;
146154
155+ // Return a guard that holds the connection. When the guard is dropped, the
156+ // connection is automatically returned to the pool, which triggers the lock release.
157+ // This design is safe and reliable - it leverages PostgreSQL's guarantee that
158+ // locks are released when a connection closes, without needing explicit unlock calls.
147159 Ok ( Box :: new ( PostgresExclusiveLockGuard {
148160 key : self . key . clone ( ) ,
149161 _conn : conn,
150162 } ) )
151163 }
152164}
153165
166+ /// Guard for a PostgreSQL shared advisory lock.
167+ ///
168+ /// This guard holds a database connection from the connection pool. When the guard is dropped
169+ /// (goes out of scope), the connection is automatically returned to the pool. PostgreSQL
170+ /// automatically releases all advisory locks held by a connection when that connection is
171+ /// closed or returned to the pool.
172+ ///
173+ /// Lock Release Mechanism:
174+ /// 1. Guard is created in acquire_shared() with the connection acquired from the pool
175+ /// 2. PostgreSQL advisory lock is held as long as the connection is active
176+ /// 3. When guard is dropped, the connection goes out of scope and is returned to the pool
177+ /// 4. PostgreSQL automatically releases the lock when the connection returns to the pool
178+ ///
179+ /// This design is superior to explicit unlock calls because:
180+ /// - No risk of forgetting to unlock (guaranteed by Rust's Drop trait)
181+ /// - No fire-and-forget async tasks that might fail to execute
182+ /// - Lock release is atomic with connection return
183+ /// - Works correctly even if the runtime is shutting down
154184struct PostgresSharedLockGuard {
155185 #[ allow( dead_code) ]
156186 key : String ,
@@ -160,6 +190,24 @@ struct PostgresSharedLockGuard {
160190
161191impl < ' a > SharedLockGuard < ' a > for PostgresSharedLockGuard { }
162192
193+ /// Guard for a PostgreSQL exclusive advisory lock.
194+ ///
195+ /// This guard holds a database connection from the connection pool. When the guard is dropped
196+ /// (goes out of scope), the connection is automatically returned to the pool. PostgreSQL
197+ /// automatically releases all advisory locks held by a connection when that connection is
198+ /// closed or returned to the pool.
199+ ///
200+ /// Lock Release Mechanism:
201+ /// 1. Guard is created in acquire_exclusive() with the connection acquired from the pool
202+ /// 2. PostgreSQL advisory lock is held as long as the connection is active
203+ /// 3. When guard is dropped, the connection goes out of scope and is returned to the pool
204+ /// 4. PostgreSQL automatically releases the lock when the connection returns to the pool
205+ ///
206+ /// This design is superior to explicit unlock calls because:
207+ /// - No risk of forgetting to unlock (guaranteed by Rust's Drop trait)
208+ /// - No fire-and-forget async tasks that might fail to execute
209+ /// - Lock release is atomic with connection return
210+ /// - Works correctly even if the runtime is shutting down
163211struct PostgresExclusiveLockGuard {
164212 #[ allow( dead_code) ]
165213 key : String ,
0 commit comments