web-dev-qa-db-fra.com

Le verrou fourni n'est pas valide. Soit le verrou a expiré, soit le message a déjà été supprimé de la file d'attente

J'utilise une file d'attente de bus de service Microsoft Azure pour traiter les calculs et mon programme fonctionne correctement pendant quelques heures, mais je commence à obtenir cette exception pour chaque message que je traite à partir de là. Je ne sais pas par où commencer car tout se passe bien pendant les premières heures. Mon code semble également exact. Je publierai la méthode dans laquelle je gère le message du bus de service Azure.

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);
        }
    }

MISE À JOUR: Je vérifie le temps jusqu'à l'expiration du verrou et j'appelle le verrouillage renouveler s'il en a besoin, mais il renouvelle le verrou sans erreur, mais je reçois toujours cette exception.

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);
        }

Tout ce que je sais jusqu'à présent, c'est que mon code fonctionne correctement pendant un certain temps et que le verrouillage de renouvellement est appelé et fonctionne, mais j'obtiens toujours l'exception de verrouillage et à l'intérieur de cette exception, je génère le timeleft et il continue d'augmenter la différence de temps pendant l'exécution du code ce qui me fait croire que le temps jusqu'à l'expiration du verrou n'est pas modifié d'une manière ou d'une autre?

27
user3610374

J'ai passé des heures à essayer de comprendre pourquoi je recevais un MessageLockLostException. La raison pour moi était due à AutoComplete par défaut à true.

Si vous allez appeler messsage.Complete() (ou CompleteAsync()), vous devez instancier un objet OnMessageOptions, définir AutoComplete sur false et le passer dans votre appel OnMessage.

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

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

J'avais un problème similaire. Les messages ont été traités avec succès, mais lorsqu'ils ont fini, le bus de service n'avait plus de verrou valide. Il s'avère que mon TopicClient.PrefetchCount était trop élevé.

Il semble que le verrouillage commence sur tous les messages prélus dès qu'ils sont récupérés. Si le temps de traitement cumulé de vos messages dépasse le délai de verrouillage, tous les autres messages prélus échouent. Il reviendra au bus de service.

6
solipsicle

Au lieu de renouveler le verrou manuellement, lorsque vous créez l'abonnement client, essayez de le renouveler automatiquement à l'aide des options OnMessage () du client, comme ceci:

        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
Botha Van Der Vyver