web-dev-qa-db-ja.com

指定されたロックは無効です。ロックの有効期限が切れているか、メッセージが既にキューから削除されています

Microsoft Azureサービスバスキューを使用して計算を処理していますが、プログラムは数時間問題なく動作しますが、それ以降、処理するすべてのメッセージに対してこの例外が発生し始めます。最初の数時間はすべて正常に動作するため、どこから始めればよいかわかりません。私のコードも正確なようです。 Azure Service Busメッセージを処理するメソッドを投稿します。

public static async Task processCalculations(BrokeredMessage message)
    {
        try
        {
            if (message != null)
            {
                if (connection == null || !connection.IsConnected)
                {
                    connection = await ConnectionMultiplexer.ConnectAsync("connection,SyncTimeout=10000,ConnectTimeout=10000");
                    //connection = ConnectionMultiplexer.Connect("connection,SyncTimeout=10000,ConnectTimeout=10000");
                }

                cache = connection.GetDatabase();

                string sandpKey = message.Properties["sandp"].ToString();
                string dateKey = message.Properties["date"].ToString();
                string symbolclassKey = message.Properties["symbolclass"].ToString();
                string stockdataKey = message.Properties["stockdata"].ToString();
                string stockcomparedataKey = message.Properties["stockcomparedata"].ToString();

                var sandpTask = cache.GetAsync<List<StockData>>(sandpKey);
                var dateTask = cache.GetAsync<DateTime>(dateKey);
                var symbolinfoTask = cache.GetAsync<SymbolInfo>(symbolclassKey);
                var stockdataTask = cache.GetAsync<List<StockData>>(stockdataKey);
                var stockcomparedataTask = cache.GetAsync<List<StockMarketCompare>>(stockcomparedataKey);

                await Task.WhenAll(sandpTask, dateTask, symbolinfoTask,
                    stockdataTask, stockcomparedataTask);

                List<StockData> sandp = sandpTask.Result;
                DateTime date = dateTask.Result;
                SymbolInfo symbolinfo = symbolinfoTask.Result;
                List<StockData> stockdata = stockdataTask.Result;
                List<StockMarketCompare> stockcomparedata = stockcomparedataTask.Result;

                StockRating rating = performCalculations(symbolinfo, date, sandp, stockdata, stockcomparedata);

                if (rating != null)
                {
                    saveToTable(rating);
                    if (message.LockedUntilUtc.Minute <= 1)
                    {
                        await message.RenewLockAsync();
                    }
                    await message.CompleteAsync(); // getting exception here
                }
                else
                {
                    Console.WriteLine("Message " + message.MessageId + " Completed!");
                    await message.CompleteAsync();
                }
            }
        }
        catch (TimeoutException time)
        {
            Console.WriteLine(time.Message);
        }
        catch (MessageLockLostException locks)
        {
            Console.WriteLine(locks.Message);
        }
        catch (RedisConnectionException redis)
        {
            Console.WriteLine("Start the redis server service!");
        }
        catch (MessagingCommunicationException communication)
        {
            Console.WriteLine(communication.Message);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
            Console.WriteLine(ex.StackTrace);
        }
    }

更新:ロックの有効期限が切れるまでの時間を確認し、必要な場合はlock renewを呼び出しますが、エラーなしでロックを更新しますが、それでもこの例外が発生します。

timeLeft = message.LockedUntilUtc - DateTime.UtcNow;
  if (timeLeft.TotalMinutes <= 2)
                    {
                        //Console.WriteLine("Renewed lock! " + ((TimeSpan)(message.LockedUntilUtc - DateTime.UtcNow)).TotalMinutes);
                        message.RenewLock();
                    }

catch (MessageLockLostException locks)
        {
            Console.WriteLine("Delivery Count: " + message.DeliveryCount);
            Console.WriteLine("Enqueued Time: " + message.EnqueuedTimeUtc);
            Console.WriteLine("Expires Time: " + message.ExpiresAtUtc);
            Console.WriteLine("Locked Until Time: " + message.LockedUntilUtc);
            Console.WriteLine("Scheduled Enqueue Time: " + message.ScheduledEnqueueTimeUtc);
            Console.WriteLine("Current Time: " + DateTime.UtcNow);
            Console.WriteLine("Time Left: " + timeLeft);
        }

私がこれまでに知っているのは、コードがしばらくの間正常に実行され、更新ロックが呼び出されて機能することですが、ロック例外が発生し、その例外の内部で、残り時間を出力し、コードが実行されるにつれて時間差が増え続けますこれにより、ロックの有効期限までの時間がどういうわけか変更されていないと思いますか?

27
user3610374

MessageLockLostExceptionを取得した理由を理解するために何時間も費やしました。私の理由は AutoComplete がデフォルトでtrueになっているためでした。

messsage.Complete()(またはCompleteAsync())を呼び出す場合は、OnMessageOptionsオブジェクトをインスタンス化し、AutoCompleteをfalseに設定して渡します。 OnMessage呼び出しに。

var options = new OnMessageOptions();
options.AutoComplete = false;

client.OnMessage(processCalculations, options);
18
Jeffrey LeCours

私は同様の問題を抱えていました。メッセージは正常に処理されていましたが、メッセージが完了すると、サービスバスには有効なロックがなくなりました。 TopicClient.PrefetchCountが高すぎることがわかりました。

プリフェッチされたすべてのメッセージがフェッチされるとすぐに、ロックが開始されるようです。累積メッセージ処理時間がロックタイムアウトを超えると、他のすべてのプリフェッチメッセージが完了できなくなります。運行バスに戻ります。

6
solipsicle

ロックを手動で更新する代わりに、クライアントサブスクリプションを作成するときに、次のようにクライアントのOnMessageOptions()を使用して自動更新を試みます。

        OnMessageOptions options = new OnMessageOptions();

        options.AutoRenewTimeout = TimeSpan.FromMinutes(1);

        try
        {
            client = Subscription.CreateClient();

            client.OnMessageAsync(MessageReceivedComplete, options);
        }
        catch (Exception ex)
        {
            throw new Exception (ex);
        }
0