Freigeben über


New Blob Lease Features: Infinite Leases, Smaller Lease Times, and More

We are excited to introduce some new features with the Lease Blob API with the 2012-02-12 version of Windows Azure Blob Storage service. The 2012-02-12 version also includes some versioned changes. This blog post covers the new features and changes as well as some scenarios and code snippets. The code snippets show how to use lease APIs using the Windows Azure Storage Client Library 1.7.1 (available on GitHub) that supports the 2012-02-12 version of the REST API.

We will begin by giving a brief description of what is new and what semantics have changed when compared to earlier versions and then deep dive into some scenarios that these changes enable. The following is the list of new features that 2012-02-12 version brings for leases:

  1. You can acquire leases for 15s up to 60s or you can acquire a lease for an infinite time period.
  2. You can change the lease id on an active lease.
  3. You can provide the lease id when trying to acquire a lease.
  4. You can provide a time period up to which a lease should continue to remain active when breaking an acquired lease.
  5. Lease is now available for containers to prevent clients from deleting a container which may be in use.

The 2012-02-12 version also brings about some versioned changes when compared to previous versions of the REST API. The following are the list of versioned changes:

  1. You have to provide lease duration when trying to acquire a lease on a blob. If the lease duration is not provided, the call to acquire a lease will fail with 400 (Bad Request). Previous versions of the API did not take lease duration as the lease duration was fixed to 60s.
  2. Once a lease is released, it cannot be broken or renewed. Breaking or renewing a lease that has been released will fail with 409 (Conflict). Previously these operations were allowed.  Applications that require a lease to be given up by calling Break Lease would now fail with 409 (Conflict). This error should be ignored since the lease is not active any more.
  3. You can now call Break Lease on a breaking or broken lease hence making break operations idempotent. In previous versions, when a lease has already been broken, a new Break Lease request failed with 409 (Conflict). Applications that want to shorten the duration of a break can now provide shorter duration than the remaining break period (See Breaking Leases section for more details).

Acquire Lease - Lease ID and Duration

Earlier versions of acquire operation did not allow users to specify the lease-id nor the duration. The duration was fixed to 60 seconds and the lease-id was determined by the service. Once a lease id was returned in the response of acquire, it could not be changed. With the 2012-02-12 version, we allow the option for users to propose the lease-id and also specify duration from 15s up to 60s or define the lease duration to be infinite.

An important property of acquire is that as long as the proposed lease-id matches the existing lease-id on a blob with an active lease, the acquire operation will succeed. The advantage of proposing the lease-id on an acquire operation is that if the acquire operation succeeds on server but fails before the server can send the response to the client (i.e. intermittent network errors), then the client can retry with the same proposed lease-id and recover from failure on success response, knowing it still holds the lease. Another property of the proposed lease-id on acquire operations is that on each successful acquire operation, the lease is set to expire once the specified duration of that operation elapses. This allows a client to change the lease duration by reissuing the acquire operation using the same proposed lease-id. Here is a sample code that acquires a lease by proposing the lease-id for 60 seconds. The code later reacquires the lease by reducing lease duration to 15 seconds. For the lease to remain active after the provided time period, the client application would need to periodically call renew before the lease period expires.

 CloudBlobClient client = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = client.GetContainerReference(containerName);
CloudBlockBlob blob = container.GetBlockBlobReference(blobName);

// acquire lease for 30s with a proposed lease id
// NOTE: null duration will acquire an infinite lease
blob.AcquireLease(TimeSpan.FromSeconds(30), leaseId);
     
   …

// re-acquire lease but reduce the duration to 15s
// could also re-acquire with increased duration, 60s for example
blob.AcquireLease(TimeSpan.FromSeconds(15), leaseId); 

 

Why would you change the lease ID?

As we mentioned above, with 2012-02-12 version, we now allow the lease id to be changed. The Change Lease operation takes the existing lease-id and proposed new id and changes the lease-id to the proposed id. Change Lease is valuable in scenarios where the lease ownership needs to be transferred from component A to component B of your system. For example, component A has a lease on a blob, but needs to allow component B to operate on it. Component B could remember the current lease-id passed to it from component A, changes it to a new lease-id, performs its operation, then change the lease-id back to the previous one that component A knows about. This would allow component B to own exclusive access to the blob, prevent the prior owner from modifying the blob until it is done, and then give access back to it.

Another example is to a workflow where, we just want to keep changing the lease-id as the blob passes through the different parts of the workflow. Let us consider a blog publishing process flow that consists of running the document through:

  1. A service that deletes all objectionable words/phrases
  2. A service that runs spell correction
  3. A service that formats the document

Each of the above steps involves changing the content of the document and is done by a separate service. In this scenario, each service will receive a lease on the document which should be maintained to ensure no one else changes the blog. In addition each service will also change the lease id to prevent previous owners from inadvertently changing the document and to ensure that only it can work on the document upon receiving the request to start processing the document. Once it completes its processing step, it will submit the request to next service in the pipeline passing it the lease id it maintained.

 string newLeaseId = Guid.NewGuid().ToString();


blob.ChangeLease(
     // new proposed leaseId
     newLeaseId, 
     // leaseId is the id received from the previous service
     AccessCondition.GenerateLeaseCondition(leaseId));

// change duration required by this service
blob.AcquireLease(TimeSpan.FromSeconds(30), newLeaseId);

 

Breaking Leases

Break operation is used to release existing lease by rejecting future requests to renew the lease and does not require the issuer to know the current lease-id being held. This is generally used by administrators to reset the lease state. In previous versions, Break Lease allows the lease to be held until the remaining time on the lease elapses. With 2012-02-12 version, this is still the default behavior, with an added option to specify the break period which defines how long to wait before the current lease expires.

The user can specify a break period between 0 and 60 seconds. However, this is only a proposed value, as the actual break period will be the minimum of this value and the remaining time left on the lease. In other words, the client will now be able to shorten the break period from the remaining time left on the lease, but not extend it.

 // If duration to break is null, it implies that lease is active for 
// remaining duration, otherwise min(break period, lease remaining time)
blob.BreakLease(TimeSpan.FromSeconds(20)); 

Infinite Leases

With 2012-02-12 version, infinite leases can be acquired by sending the lease duration to be -1 for the REST API. The storage client library’s Acquire Lease allows null to be passed in as duration to acquire the infinite lease. An infinite lease will never expire, unless explicitly released or broken and hence acts like a lock.

 blob.AcquireLease(null /* infinite lease */, leaseId);
// Note: Acquire can be called again with a valid duration to convert an 
// infinite lease to a finite one.
  

A useful scenario for infinite leases could be for a blob used by a client that wishes to have a lease on at all times (i.e. acquire a lock on the blob). Instead of having to renew the lease continuously as in previous versions, the client now just needs one acquire to specify infinite lease duration.

For Break Lease on an infinite lease, the default behavior is to break the lease immediately. The break operation also has the option for duration to be specified for the break period.

Container Leases

We have added the Lease Container API to prevent container deletion. Holding a lease on a container does not prevent anyone from adding, deleting, or updating any blob content in the container. This is meant to only prevent deletion of the container itself. The lease operations provided are similar to those provided on the blob with the only exception that the lease is a “delete” lease. The operations are:

  • Acquire lease – Issuer must provide lease duration and optionally propose lease-id
  • Change lease-id - to allow changing the current id to a new lease-id
  • Renew lease - to renew the duration
  • Break lease - to break existing lease without having knowledge of existing lease-id
  • Release lease - so that another prospective owner can acquire the lease

Consider a scenario where all blobs need to be moved to a different account. Multiple instances can be used in parallel and each instance will work on a given container. When an instance of the job starts, it acquires an infinite lease on the container to prevent anyone from deleting the container prematurely. In addition, since an instance would try to acquire a lease, it will fail if the container is being worked on by a different instance – hence preventing two job instances from migrating the same container.

 CloudBlobClient client = storageAccount.CreateCloudBlobClient();
// each migration job is assigned a fixed instance id and it will be used 
// as the lease id.
string leaseId = instanceId; 
IEnumerable<CloudBlobContainer> containerList = client.ListContainers();

foreach (CloudBlobContainer container in containerList)
{
    try
    {
        container.AcquireLease(null /* Infinite lease */, leaseId);
        // if successful - start migration job which will delete the container 
        // once it completes migration 
          …
    }
    catch (Exception e)
    {
        // Check for lease conflict exception – implies some other instance 
        // is working on this container
    }
 }

Lease Properties

With 2012-02-12 version and later the service returns lease specific properties for container and blobs on List Containers, List Blobs, Get Container Properties, Get Blob Properties and Get Blob . The lease specific properties returned are:

x-ms-lease-status (or LeaseStatus): Returns the status of the lease on the blob or container. The possible values are locked or unlocked.

x-ms-lease-state (or LeaseState): Returns the state of the lease on the blob or container. The possible values are available, leased, expired, breaking, or broken. This information can be used by applications for diagnostics or to take further action. For example: If the lease is in breaking, broken or expired state, one of the redundant master instances may try to acquire the lease.

While the lease status tells you if the lease is active or not, the lease state property provides more granular information. Example – the lease status may be locked but state may be breaking.

x-ms-lease-duration (or LeaseDuration): Returns the duration type of the lease – finite or infinite.

Weiping Zhang, Michael Roberson, Jai Haridas, Brad Calder

Comments

  • Anonymous
    July 28, 2013
    I do not understand what is the result of the  AcquireLease ("acquire a lock on the blob") in case of the resource is locked by somebody else? Exception? What kind of exception? Or the thread will be just wait for blob become unlocked?  Can you document this?

  • Anonymous
    July 28, 2013
    Hi Roman, The operation will fail with 409 i.e. conflict (and does not wait for lease to be available). You will get an exception with status code 409. Thanks, jai

  • Anonymous
    July 28, 2013
    Hi Roman, Please also note the lone exception to 409 (Conflict) is when AcquireLease is made with x-ms-proposed-lease-id equal to the active lease, in which case the call would succeed with 201 (Created). For more details please see our MSDN LeaseBlob documentation (msdn.microsoft.com/.../ee691972.aspx), specifically the “Outcomes of lease operations on blobs by lease state” table provides expected behaviors of the LeaseBlob API given the blob’s current lease state. Thanks, Weiping

  • Anonymous
    March 18, 2015
    I tried the code you have to acquire a lease on the container, but it returns with a "The remote server returned an error: (400) Bad Request." error. Any ideas?

  • Anonymous
    March 19, 2015
    The comment has been removed