The issue is resolved in the latest version of the Windows Azure SDK which can be downloaded here.
We have received a few reports of problems when using the following APIs in Windows Azure Storage Client Library (WA SCL) for Windows Azure Tables and the following routines:
- Using CloudTableQuery to iterate query results or using BeginExecuteSegmented/EndExecutedSegment
- BeginSaveChanges/EndSaveChanges in WCF Data Service Client library
- BeginExecuteQuery/EndExecuteQuery in WCF Data Service Client library
The problems can surface in any one of these forms:
- Incomplete callbacks in WCF Data Service client library which can lead to 90 second delays
- NotSupported Exception – the stream does not support concurrent IO read or write operations
System.IndexOutOfRangeException – probable I/O race condition detected while copying memory
This issue stems from a bug in asynchronous APIs (BeginSaveChanges/EndSaveChanges and BeginExecuteQuery/EndExecuteQuery) provided by WCF Data Service which has been fixed in .NET 4.0 and .NET 3.5 SP1 Update. However, this version of .NET 3.5 is not available in the Guest OS and SDK 1.1 does not support hosting your application in .NET 4.0.
The available options for users to deal with this are:
- Rather than using the WA SCL Table APIs that provide continuation token handling and retries, use the WCF Data Service synchronous APIs directly until .NET 3.5 SP1 Update is available in the cloud.
- As a work around, if the application is fine with dealing with the occasional delay from using the unpatched version of .NET 3.5, the application can look for the StorageClientException with the message “Unexpected Internal Storage Client Error” and status code “HttpStatusCode.Unused”. On occurrence of such an exception, the application should dispose of the context that was being used and this context should not be reused for any other operation as recommended in the workaround.
- Use the next version of the SDK when it comes out, since it will allow your application to use .NET 4.0
To elaborate a little on option 1, when a CUD operation needs to be performed, one can use the synchronous WCF Data Service API to avoid the problem mentioned above. The following code shows an example:
CloudTableClient tableClient = new CloudTableClient( account.TableEndpoint.AbsoluteUri, account.Credentials); TableServiceContext context = tableClient.GetDataServiceContext(); // Replace context.SaveChangesWithRetries() with the following context.SaveChanges();
The WA SCL handled retries for you and if you use bare bones WCF Data Services client library, you would need to provide your own retry logic. However, our previous posts have examples on how to wrap your own functionality with retry logic and they provide the basic functions for providing retry. To get into the details - you can wrap it with an extension method that implements the retry logic similar to how we added retries to the CreateSnapshot method in the “Protecting Your Blobs Against Application Errors” post. The methods GetStatusCodeFromException and IsExceptionRetryable are generic enough to be used for Tables and the logic of retrying the operation on all “retryable” errors using the retry strategy is useful to implement your own implementation of extension methods.
For queries, you can enumerate over the IQueryable rather than converting it to CloudTableQuery which uses WCF Data Service’s async API. A crucial point to note here is that the application would have to handle continuation tokens and retry each query request. For continuation token handling please refer to the Windows Azure Table technical documentation that provides an example. The above mention retry strategy can be used for queries too.
Hope this post helps and as always, please do send feedback our way.