This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Distributed lock

Distributed locks provide mutually exclusive access to shared resources from an application.

1 - Distributed lock overview

Overview of the distributed lock API building block

Introduction

Locks are used to provide mutually exclusive access to a resource. For example, you can use a lock to:

  • Provide exclusive access to a database row, table, or an entire database
  • Lock reading messages from a queue in a sequential manner

Any resource that is shared where updates occur can be the target for a lock. Locks are usually used on operations that mutate state, not on reads.

Each lock has a name. The application determines the resources that the named lock accesses. Typically, multiple instances of the same application use this named lock to exclusively access the resource and perform updates.

For example, in the competing consumer pattern, multiple instances of an application access a queue. You can decide that you want to lock the queue while the application is running its business logic.

In the diagram below, two instances of the same application, App1, use the Redis lock component to take a lock on a shared resource.

  • The first app instance acquires the named lock and gets exclusive access.
  • The second app instance is unable to acquire the lock and therefore is not allowed to access the resource until the lock is released, either:
    • Explicitly by the application through the unlock API, or
    • After a period of time, due to a lease timeout.

*This API is currently in Alpha state.

Features

Mutually exclusive access to a resource

At any given moment, only one instance of an application can hold a named lock. Locks are scoped to a Dapr app-id.

Deadlock free using leases

Dapr distributed locks use a lease-based locking mechanism. If an application acquires a lock, encounters an exception, and cannot free the lock, the lock is automatically released after a period of time using a lease. This prevents resource deadlocks in the event of application failures.

Demo

Watch this video for an overview of the distributed lock API:

Next steps

Follow these guides on:

2 - How-To: Use a lock

Learn how to use distributed locks to provide exclusive access to a resource

Now that you’ve learned what the Dapr distributed lock API building block provides, learn how it can work in your service. In this guide, an example application acquires a lock using the Redis lock component to demonstrate how to lock resources. For a list of supported lock stores, see this reference page.

In the diagram below, two instances of the same application acquire a lock, where one instance is successful and the other is denied.

The diagram below shows two instances of the same application acquiring a lock, where one instance is successful and the other is denied

The diagram below shows two instances of the same application, where one instance releases the lock and the other instance is then able to acquire the lock.

Diagram showing releasing a lock from multiple instances of same application

The diagram below shows two instances of different applications, acquiring different locks on the same resource.

The diagram below shows two instances of different applications, acquiring different locks on the same resource

Configure a lock component

Save the following component file to the default components folder on your machine.

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: lockstore
spec:
  type: lock.redis
  version: v1
  metadata:
  - name: redisHost
    value: localhost:6379
  - name: redisPassword
    value: <PASSWORD>

Acquire lock

curl -X POST http://localhost:3500/v1.0-alpha1/lock/lockstore
   -H 'Content-Type: application/json'
   -d '{"resourceId":"my_file_name", "lockOwner":"random_id_abc123", "expiryInSeconds": 60}'
using System;
using Dapr.Client;

namespace LockService
{
    class Program
    {
        [Obsolete("Distributed Lock API is in Alpha, this can be removed once it is stable.")]
        static async Task Main(string[] args)
        {
            string DAPR_LOCK_NAME = "lockstore";
            string fileName = "my_file_name";
            var client = new DaprClientBuilder().Build();
    
            await using (var fileLock = await client.Lock(DAPR_LOCK_NAME, fileName, "random_id_abc123", 60))
            {
                if (fileLock.Success)
                {
                    Console.WriteLine("Success");
                }
                else
                {
                    Console.WriteLine($"Failed to lock {fileName}.");
                }
            }
        }
    }
}
package main

import (
    "fmt"

    dapr "github.com/dapr/go-sdk/client"
)

func main() {
    client, err := dapr.NewClient()
    if err != nil {
        panic(err)
    }
    defer client.Close()
    
    resp, err := client.TryLockAlpha1(ctx, "lockstore", &dapr.LockRequest{
			LockOwner:         "random_id_abc123",
			ResourceID:      "my_file_name",
			ExpiryInSeconds: 60,
		})

    fmt.Println(resp.Success)
}

Unlock existing lock

curl -X POST http://localhost:3500/v1.0-alpha1/unlock/lockstore
   -H 'Content-Type: application/json'
   -d '{"resourceId":"my_file_name", "lockOwner":"random_id_abc123"}'
using System;
using Dapr.Client;

namespace LockService
{
    class Program
    {
        static async Task Main(string[] args)
        {
            string DAPR_LOCK_NAME = "lockstore";
            var client = new DaprClientBuilder().Build();

            var response = await client.Unlock(DAPR_LOCK_NAME, "my_file_name", "random_id_abc123"));
            Console.WriteLine(response.status);
        }
    }
}
package main

import (
    "fmt"

    dapr "github.com/dapr/go-sdk/client"
)

func main() {
    client, err := dapr.NewClient()
    if err != nil {
        panic(err)
    }
    defer client.Close()
    
    resp, err := client.UnlockAlpha1(ctx, "lockstore", &UnlockRequest{
			LockOwner:    "random_id_abc123",
			ResourceID: "my_file_name",
		})

    fmt.Println(resp.Status)
}

Next steps

Read the distributed lock API overview to learn more.