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
PostgresDistributedLockclass implements theIDistributedLockinterface. - The
PostgresDistributedReaderWriterLockclass implements theIDistributedReaderWriterLockinterface. - The
PostgresDistributedSynchronizationProviderclass implements theIDistributedLockProviderandIDistributedReaderWriterLockProviderinterfaces.
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
longvalue. - Passing a pair of
intvalues. - 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 ofints. - Passing an ASCII string with 0-9 characters, which will be mapped to a
longbased on a custom scheme. - Passing an arbitrary string with the
allowHashingoption set totruewhich 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:
KeepaliveCadenceallows 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).UseTransactionscopes 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.UseMultiplexingallows 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!).