Sproc.Lock

Documentation

The Sproc.Lock library can be installed from NuGet:
PM> Install-Package Sproc.Lock

Example

Take a distributed lock in a shared SQL Server database.

In F#:

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
#r "Sproc.Lock.dll"
open System
open Sproc.Lock.Fun

let connString = "sql server connection string"

let lock1 = GetGlobalLock connString (TimeSpan.FromMinutes 5.) "MyAppLock"

match lock1 with
| Locked l ->
    sprintf "I got a lock called %s!" l.LockId
    // (will be "MyAppLock" on this occassion)
| Unavailable ->
    sprintf "Someone else had the lock already!"
| Error i ->
    sprintf "Something went wrong - error code: %d" i

lock1.Dispose()

And C#:

using System;
using Sproc.Lock.OO;


namespace MyApp
{
    class Thing
    {
        static void DoLockRequiringWork()
        {
            var provider = new LockProvider("sql connection string");
            try
            {
                using (var lock2 = provider.GlobalLock("MyAppLock", TimeSpan.FromMinutes(5.0)))
                {
                    // If I get here, I have a lock!                    
                    // Doing stuff!
                } // Lock released when Disposed
            }
            catch (LockUnavailableException)
            {
                // Could not get the lock                
                throw;
            }
            catch (LockRequestErrorException)
            {
                // Getting the lock threw an error
                throw;
            }
        }
    }
}

Documentation

Sproc.Lock is a combination of a managed .net library and a set of SQL Server scripts that combine to turn SQL Server into a distributed locking server.

This library is only really recommended if you are already using SQL Server, and do not have a more suitable distibuted locking server already up and running. In that case, Sproc.Lock can save you the overhead of adding an additional piece of infrastructure to your environment.

Basic Concepts

Sproc.Lock makes use of a few concepts that might not be immediately obvious.

Firstly, all methods that acquire a lock must specify a maximum duration it will be held for. This is essential in distributed locking systems, as otherwise a crashing/abnormally behaving service may acquire a lock and never release it.

Secondly, Sproc.Lock has three levels of scoping a lock. Locks can be acquired as:

  • Global - no other global lock with the same lock id can be acquired at the same time
  • Organisation - an organisation id is also specified, and locks with the same id can be held by multiple organisations
  • Environment - an organisation id and environment type are specified; locks are scoped within both

This is designed to cope with the common situations of having resources that are available in limited number:

  • across a data centre
  • across an client organisation
  • within a particular environment (i.e. Production, Test, etc)

Find Out More!

  • Tutorial contains a further explanation of Sproc.Lock.

  • API Reference contains automatically generated documentation for all types, modules and functions in the library. This includes additional brief samples on using most of the functions.

Contributing and copyright

The project is hosted on GitHub where you can report issues, fork the project and submit pull requests. If you're adding a new public API, please also consider adding samples that can be turned into a documentation. You might also want to read the library design notes to understand how it works.

The library is available under Public Domain license, which allows modification and redistribution for both commercial and non-commercial purposes. For more information see the License file in the GitHub repository.

namespace System
namespace Sproc
namespace Sproc.Lock
module Fun

from Sproc.Lock
val connString : string

Full name: Index.connString
val lock1 : LockResult

Full name: Index.lock1
val GetGlobalLock : connString:string -> maxDuration:TimeSpan -> lockIdentifier:string -> LockResult

Full name: Sproc.Lock.Fun.GetGlobalLock
Multiple items
type TimeSpan =
  struct
    new : ticks:int64 -> TimeSpan + 3 overloads
    member Add : ts:TimeSpan -> TimeSpan
    member CompareTo : value:obj -> int + 1 overload
    member Days : int
    member Duration : unit -> TimeSpan
    member Equals : value:obj -> bool + 1 overload
    member GetHashCode : unit -> int
    member Hours : int
    member Milliseconds : int
    member Minutes : int
    ...
  end

Full name: System.TimeSpan

--------------------
TimeSpan()
TimeSpan(ticks: int64) : unit
TimeSpan(hours: int, minutes: int, seconds: int) : unit
TimeSpan(days: int, hours: int, minutes: int, seconds: int) : unit
TimeSpan(days: int, hours: int, minutes: int, seconds: int, milliseconds: int) : unit
TimeSpan.FromMinutes(value: float) : TimeSpan
union case LockResult.Locked: Lock -> LockResult
val l : Lock
val sprintf : format:Printf.StringFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.sprintf
property Lock.LockId: string
union case LockResult.Unavailable: LockResult
union case LockResult.Error: int -> LockResult
val i : int
member LockResult.Dispose : unit -> unit
Fork me on GitHub