The DistributedLock.Postgres package offers distributed synchronization primitives based on PostgreSQL advisory locks. For example:
var @lock = new PostgresDistributedLock(new PostgresAdvisoryLockKey("MyLockName", allowHashing: true), connectionString);
await using (await @lock.AcquireAsync())
{
// I have the lock
}
- The
PostgresDistributedLock
class implements theIDistributedLock
interface. - The
PostgresDistributedReaderWriterLock
class implements theIDistributedReaderWriterLock
interface. - The
PostgresDistributedSynchronizationProvider
class implements theIDistributedLockProvider
andIDistributedReaderWriterLockProvider
interfaces.
Under the hood, Postgres advisory locks can be based on either one 64-bit integer value or a pair of 32-bit integer values. Because of this, rather than taking in a name the lock constructors take a PostgresAdvisoryLockKey
object which can be constructed in several ways:
- Passing a single
long
value. - Passing a pair of
int
values. - Passing a 16-character hex string (e. g.
"00000003ffffffff"
) which will be parsed as along
. - Passing a pair of comma-separated 8-character hex strings (e. g.
"00000003,ffffffff"
) which will be parsed as a pair ofint
s. - Passing an ASCII string with 0-9 characters, which will be mapped to a
long
based on a custom scheme. - Passing an arbitrary string with the
allowHashing
option set totrue
which will be hashed to along
. Note that hashing will only be used if other methods of interpreting the string fail.
In addition to specifying the key
, Postgres-based locks allow you to specify either a connectionString
, an IDbConnection
, or a DbDataSource
as a means of connecting to the database. In most cases, using a connectionString
is preferred because it allows for the library to efficiently multiplex connections under the hood and, in the case of IDbConnection
, eliminates the risk that the passed-in IDbConnection
gets used in a way that disrupts the locking process. NOTE that since IDbConnection
objects are not thread-safe, lock objects constructed with them can only be used by one thread at a time.
In addition to specifying the key
, several tuning options are available for connectionString
-based locks:
KeepaliveCadence
allows you to have the implementation periodically issue a cheap query on a connection holding a lock. This helps in configurations which are set up to aggressively kill idle connections. Defaults to OFF (Timeout.InfiniteTimeSpan
).UseTransaction
scopes the lock to an internally-managed transaction under the hood (otherwise it is connection-scoped). Defaults to FALSE because this mode is not compatible with multiplexing and thus consumes more connections.UseMultiplexing
allows the implementation to re-use connections under the hood to hold multiple locks under certain scenarios, leading to lower resource consumption. This behavior defaults to ON; you should not disable it unless you suspect that it is causing issues for you (please file an issue here if so!).