从错误云计算Azure的表删除 - ResourceNotFound [英] Error deleting from Azure Cloud Table - ResourceNotFound

查看:508
本文介绍了从错误云计算Azure的表删除 - ResourceNotFound的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个间歇性问题,从一个蓝色的表中删除的对象。它只会影响我尝试的1%左右,而如果相同的呼叫再次作出后那么它工作正常,但我很想找出背后的原因!我用Google搜索过我的手指,我发现缺少文档在那里如何建立非常可靠的code删除,插入和更新是相当令人惊讶......这一切似乎有点击中小姐,试试吧,大多数时间它会工作

I'm having an intermittent problem deleting objects from an azure table. It only affects about 1% of my attempts, and if the same call is made again later then it works fine, but I'd love to find out the reason behind it! I've googled my fingers off and I've found the lack of documentation out there on how to create very reliable code for deleting, inserting and updating to be quite surprising ... it all seems to be a bit hit and miss, "try it, most of the time it will work"

编辑:我删除了原本在这个问题的文本和全新的文字要考虑的事情,我已经试过/已建议将它

做天青从表像SQL Azure的间歇性故障受到影响。如果是这样,我会虽然saveChangesWithRetries会处理吗?这是错的?

Do Azure Tables suffer from intermittent failures like SQL Azure. If so, I would have though the "saveChangesWithRetries" would have dealt with that? Is this wrong?

所以...相当简单code,被称为上Azure的网络角色分钟约250次。蔚蓝表被用作消息传送系统的一部分。消息由一个用户,另一个下载插入,在下载成功为已读的邮件标记。

So ... fairly simply code, being called about 250 times a minute on an Azure web-role. The azure tables are used as part of a messaging system. Messages are inserted by one user, downloaded by another, on successful download those messages are marked as read.

每个用户有未读消息的分区,并为已读邮件的分区。作为读,它是由未读分区删除和移动到读取分区,这样标记的消息。

Each user has a partition for unread messages, and a partition for read messages. So to mark a message as "read", it is deleted from the unread partition and moved into the read partition.

250时该code为每分钟叫,我就2和最终SaveChangesWithRetries以下错误10之间接收()。内部的例外是:

Of the 250 time this code is called per minute, I'll receive between 2 and 10 of the following errors on the final SaveChangesWithRetries(). The inner exception is:


   ResourceNotFound
  指定的资源不存在。
  请求ID:652a3e13-3911-4503-8e49-6fec32a3c044
  时间:2011-09-28T22:09:39.0795651Z

ResourceNotFound The specified resource does not exist. RequestId:652a3e13-3911-4503-8e49-6fec32a3c044 Time:2011-09-28T22:09:39.0795651Z

我不想像一个单独的分区被访问超过一分钟几次。

I do not imagine an individual partition being accessed more than a few times a minute.

这是我的code:

    public static void Message_MarkAsRead(int uid)
    {
        try
        {
            storageAccount = CloudStorageAccount.Parse(connectionString);
            tableClient = new CloudTableClient(storageAccount.TableEndpoint.AbsoluteUri, storageAccount.Credentials);
            tableClient.RetryPolicy = RetryPolicies.Retry(retryAmount, TimeSpan.FromSeconds(retrySeconds));

            TableServiceContext tableServiceContext = tableClient.GetDataServiceContext();
            tableServiceContext.IgnoreResourceNotFoundException = true;

            //the messageUserJoinerTable let's us join messageId to userFromId and userToId
            //each message is inserted into the tables twice, once into the userFromId partition and also into the userToId partition
            #region get the userToId and userFromId for this message uid
            List<int> userIds = new List<int>();
            var resultsUserIds = from messagesUserJoinerTable in tableServiceContext.CreateQuery<MessageUserJoinerDataEntity>(messageUserJoinerTableName)
                                where messagesUserJoinerTable.PartitionKey == uid.ToString()
                                select messagesUserJoinerTable;

            foreach (MessageUserJoinerDataEntity messageUserJoiner in resultsUserIds)
            {
                userIds.Add(messageUserJoiner.UserId);
            }
            #endregion

            #region then we need to check the partition for each of these users and mark the messages as read
            if (userIds.Count > 0)
            {
                foreach (int userId in userIds)
                {
                    var resultsUnreadMessages = from messagesTable in tableServiceContext.CreateQuery<MessageDataEntity>(messageTableName)
                                                where messagesTable.PartitionKey == CreatePartitionKey(userId, false)
                                                && messagesTable.RowKey == CreateRowKey(uid)
                                                select messagesTable;

                    //there should only ever be one as duplicate partition/rowkey is not allowed
                    MessageDataEntity messageUnread = resultsUnreadMessages.FirstOrDefault();

                    if (messageUnread != null)
                    {
                        bool isUnreadMessageDeleted = false;

                        //shallow copy the message for re-inserting as read
                        MessageDataEntity messageRead = new MessageDataEntity(messageUnread);

                        //delete the message
                        try
                        {
                            tableServiceContext.Detach(messageUnread);
                            tableServiceContext.AttachTo(messageTableName, messageUnread, "*");
                            tableServiceContext.DeleteObject(messageUnread);
                            //this is where the error occurs
                            tableServiceContext.SaveChangesWithRetries();

                            isUnreadMessageDeleted = true;
                        }
                        catch (Exception ex)
                        {
                            MyTrace.Trace("AzureCloudTable_" + Service.versionForTracing + ".Message_MarkAsRead. Error.Stage.1: MessageID:" + uid + ", UserID:" + userId + ". " + ex.Message + ex.StackTrace + ", " + ex.InnerException.Message + ex.InnerException.StackTrace, "Error. MarkAsRead");

                            //check to see if the message we tried to delete has already been deleted
                            //if so, we just consume this error and continue by inserting the read message
                            //else, we throw the exception outwards
                            var resultsUnreadMessagesLastCheck = from messagesTable in tableServiceContext.CreateQuery<MessageDataEntity>(messageTableName)
                                                                 where messagesTable.PartitionKey == CreatePartitionKey(userId, false)
                                                                 && messagesTable.RowKey == CreateRowKey(uid)
                                                                 select messagesTable;

                            //there should only ever be one as duplicate partition/rowkey is not allowed
                            MessageDataEntity messageUnreadLastCheck = resultsUnreadMessages.FirstOrDefault();

                            if (messageUnreadLastCheck != null)
                            {
                                MyTrace.Trace("AzureCloudTable_" + Service.versionForTracing + ".Message_MarkAsRead. Error.Stage.2: MessageID:" + uid + ", UserID:" + userId + ". Message WAS deleted.", "Error. MarkAsRead");

                                //the message IS deleted, so although I don't understand why getting error in the first 
                                //place, the result should be the same
                                throw ex;
                            }
                            else
                            {
                                //the message is NOT deleted, so we may as well give up now as I don't understand
                                //what's going on
                                MyTrace.Trace("AzureCloudTable_" + Service.versionForTracing + ".Message_MarkAsRead. Error.Stage.2: MessageID:" + uid + ", UserID:" + userId + ". Message was NOT deleted.", "Error. MarkAsRead");
                            }
                        }

                        //mark the new message as read
                        if (isUnreadMessageDeleted)
                        {
                            messageRead.PartitionKey = CreatePartitionKey(userId, true);
                            messageRead.IsRead = true;

                            //check if read message already exists in storage, if not, insert
                            var resultsReadMessages = from messagesTable in tableServiceContext.CreateQuery<MessageDataEntity>(messageTableName)
                                                      where messagesTable.PartitionKey == CreatePartitionKey(userId, true)
                                                      && messagesTable.RowKey == CreateRowKey(uid)
                                                      select messagesTable;

                            //do the insert
                            if (resultsReadMessages.FirstOrDefault() == null)
                            {
                                tableServiceContext.AddObject(messageTableName, messageRead);
                                tableServiceContext.SaveChangesWithRetries();
                            }
                        }
                    }
                }
            }
            #endregion
        }
        catch (Exception ex)
        {
            try
            {
                MyTrace.Trace("AzureCloudTable_" + Service.versionForTracing + ".Message_MarkAsRead. Error: " + ex.Message + ex.StackTrace + ", " + ex.InnerException.Message + ex.InnerException.StackTrace, "Error. MarkAsRead");
            }
            catch (Exception)
            {
                MyTrace.Trace("AzureCloudTable_" + Service.versionForTracing + ".Message_MarkAsRead. Error: " + ex.Message + ex.StackTrace, "Error. MarkAsRead");
            }
        }
    }

我不明白是怎么的资源都可能不存在,当它被送回了我作为查询的一部分,然后我做就可以了!= NULL检查。

I don't understand how the resource can possible not exist, when it's been returned to me as part of the query and then I've done a != null check on it.

,我加了code做额外的检查中试一试,看是否该对象已被不小心删除。 它并没有被删除

Based on previous responses, I added code to do an additional check in the try to see if the object has already been deleted somehow. it has not been deleted

我的跟踪上返回一个错误是:

My tracing returns this on an error:

AzureCloudTable_3_0_5.Message_MarkAsRead。 Error.Stage.1:邮件ID:146751012,BoyID:477296。处理此请求时出错。在Microsoft.WindowsAzure.StorageClient.Tasks.Task 1.get_Result()在Microsoft.WindowsAzure.StorageClient.Tasks.Task 1.ExecuteAndWait()在BenderRestfulService_3_0_5.AzureCloudTable.Message_MarkAsRead( INT32 UID)在... ResourceNotFound 指定的资源不存在。请求ID:583c59df-FDAC-47e4-a03c-7a4bc7d004c9时间:2011-10-05T16:37:36.7940530Z在System.Data.Services.Client.DataServiceContext.SaveResult.d__1e.MoveNext()

AzureCloudTable_3_0_5.Message_MarkAsRead. Error.Stage.1: MessageID:146751012, BoyID:477296. An error occurred while processing this request. at Microsoft.WindowsAzure.StorageClient.Tasks.Task1.get_Result() at Microsoft.WindowsAzure.StorageClient.Tasks.Task1.ExecuteAndWait() at BenderRestfulService_3_0_5.AzureCloudTable.Message_MarkAsRead(Int32 uid) in ... ResourceNotFound The specified resource does not exist. RequestId:583c59df-fdac-47e4-a03c-7a4bc7d004c9 Time:2011-10-05T16:37:36.7940530Z at System.Data.Services.Client.DataServiceContext.SaveResult.d__1e.MoveNext()

AzureCloudTable_3_0_5.Message_MarkAsRead。 Error.Stage.2:邮件ID:146751012,BoyID:477296。消息未被删除。

AzureCloudTable_3_0_5.Message_MarkAsRead. Error.Stage.2: MessageID:146751012, BoyID:477296. Message was NOT deleted.

我完全莫名其妙。任何意见大大AP preciated!

I am utterly baffled. Any advice greatly appreciated!!!

史蒂芬

推荐答案

问题解决了,我来解释一下我发现的情况下,它有利于任何人。

Problem solved, and I'll explain what I found in case it benefits anyone else.

这是因为线程(由Smarx躲避到),事实证明我的想法是像SQL开发人员,而我会考虑在Azure code和缺乏真正的一些非常奇怪的/意外的行为深入的例子!

It was due to threading (as eluded to by Smarx), the fact that I was thinking like a SQL developer, and what I would consider some rather odd/unexpected behaviour by the Azure code and a real lack of in-depth examples!

因此​​,要解决这个问题我简化尽可能的问题。

So, to solve it I simplified the problem as much as possible.

我创建了一个包含一个实体,PartitionKey'a'的表,RowKey'1'。

I created a table that contained one entity, PartitionKey 'a', RowKey '1'.

我创建了一个选择的A从表中删除,将其改为B,并重新插入它一个控制台应用程序。

I created a console app that selected 'a' from the table, deleted it, changed it to 'b' and re-inserted it.

我跑了code上一个循环,上千次,而这一切工作的罚款。

I ran the code on a loop, thousands of times, and it all worked fine.

然后我感动code成线,并推出两个线程。我立刻被击中错误和地方失去了删除和插入的实体。

I then moved the code into a thread, and launched two threads. Immediately I was hit with errors and lost the entity somewhere between a delete and an insert.

问题1:两个线程可以同时在同一选择实体,既可以检查,看它是否存在,那么既可以尝试将其删除。只有当删除它一会取得成功。所以,你需要捕获错误,请检查该错误包含ResourceNotFound,如果是这样相信的对象真的走了,并继续正常。

Problem 1: The two threads can both select the entity at the same, both can check to see if it exists, then both can try and delete it. Only one will succeed when deleting it. So you need to catch the error, check that the error contains "ResourceNotFound", and if so trust that the object is really gone and continue as normal.

问题2:tableContext记住上次失败的操作,所以在这里删除失败的线程将抛出另一个错误上SaveChangesWithRetries你打电话ADDOBJECT后。所以,你需要使用一个新的tableContext为ADDOBJECT

Problem 2: The tableContext remembers the last failed action, so the thread where the delete failed will throw another error on SaveChangesWithRetries after you call AddObject. So you need to use a new tableContext for the AddObject

问题3:这两个线程都在增加实体的机会,但只有一个会成功。即使两个线程检查,看看是否对象添加它之前存在,他们可能都认为它不存在,并都试图添加它。所以为了简单起见,让两个线程尝试添加它,一会成功,一会抛出一个EntityAlreadyExists错误。正好赶上这个错误并继续。

Problem 3: Both threads have a chance at adding the entity, but only one will succeed. Even if both threads check to see if the objects exists before adding it, they could both think that it does NOT exist and both attempt to add it. So for simplicity, let both threads try and add it, one will succeed and one will throw an "EntityAlreadyExists" error. Just catch this error and continue.

这是我的工作code这个简单的例子,我修改为我在原来的问题更加复杂的例子,现在根本得不到任何错误。

Here is my working code for this simple example, I modified it for my more complex example in the original question and now receive no errors at all.

    //method for shifting an entity backwards and forwards between two partitions, a and b
    private static void Shift(int threadNumber)
    {
        Console.WriteLine("Launching shift thread " + threadNumber);

        //set up access to the tables
        _storageAccount = CloudStorageAccount.Parse(_connectionString);
        _tableClient = new CloudTableClient(_storageAccount.TableEndpoint.AbsoluteUri, _storageAccount.Credentials);
        _tableClient.RetryPolicy = RetryPolicies.Retry(_retryAmount, TimeSpan.FromSeconds(_retrySeconds));

        int lowerLimit = threadNumber * _limit;
        int upperLimit = (threadNumber + 1) * _limit;

        for (int i = lowerLimit; i < upperLimit; i++)
        {
            try
            {
                TableServiceContext tableServiceContextDelete = _tableClient.GetDataServiceContext();
                tableServiceContextDelete.IgnoreResourceNotFoundException = true;

                string partitionKey = "a";

                if (i % 2 == 1)
                {
                    partitionKey = "b";
                }

                //find the object with this partition key
                var results = from table in tableServiceContextDelete.CreateQuery<TableEntity>(_tableName)
                              where table.PartitionKey == partitionKey
                                && table.RowKey == "1"
                              select table;

                TableEntity tableEntity = results.FirstOrDefault();

                //shallow copy it
                if (tableEntity != null)
                {
                    TableEntity tableEntityShallowCopy = new TableEntity(tableEntity);

                    if (tableEntityShallowCopy.PartitionKey == "a")
                    {
                        tableEntityShallowCopy.PartitionKey = "b";
                    }
                    else
                    {
                        tableEntityShallowCopy.PartitionKey = "a";
                    }

                    //delete original
                    try
                    {
                        tableServiceContextDelete.Detach(tableEntity);
                        tableServiceContextDelete.AttachTo(_tableName, tableEntity, "*");
                        tableServiceContextDelete.DeleteObject(tableEntity);
                        tableServiceContextDelete.SaveChangesWithRetries();
                        Console.WriteLine("Thread " + threadNumber + ". Successfully deleted. PK: " + tableEntity.PartitionKey);
                    }
                    catch (Exception ex1)
                    {
                        if (ex1.InnerException.Message.Contains("ResourceNotFound"))
                        {
                            //trying to delete an object that's already been deleted so just continue
                        }
                        else
                        {
                            Console.WriteLine("Thread " + threadNumber + ". WTF?! Unexpected error during delete. Code: " + ex1.InnerException.Message);
                        }
                    }

                    //move into new partition (a or b depending on where it was taken from)
                    TableServiceContext tableServiceContextAdd = _tableClient.GetDataServiceContext();
                    tableServiceContextAdd.IgnoreResourceNotFoundException = true;

                    try
                    {
                        tableServiceContextAdd.AddObject(_tableName, tableEntityShallowCopy);
                        tableServiceContextAdd.SaveChangesWithRetries();
                        Console.WriteLine("Thread " + threadNumber + ". Successfully inserted. PK: " + tableEntityShallowCopy.PartitionKey);
                    }
                    catch (Exception ex1)
                    {
                        if (ex1.InnerException.Message.Contains("EntityAlreadyExists"))
                        {
                            //trying to add an object that already exists, so continue as normal
                        }
                        else
                        {
                            Console.WriteLine("Thread " + threadNumber + ". WTF?! Unexpected error during add. Code: " + ex1.InnerException.Message);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error shifting: " + i + ". Error: " + ex.Message + ". " + ex.InnerException.Message + ". " + ex.StackTrace);
            }
        }

        Console.WriteLine("Done shifting");
    }

我敢肯定有这样做的好得多的方式,但由于缺乏很好的例子,我只是用一些对我的作品去!

I'm sure there are much nicer ways of doing this, but due to the lack of good examples I'm just going with something that works for me!

感谢

这篇关于从错误云计算Azure的表删除 - ResourceNotFound的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆