Trasferimenti, blocchi e finalizzazione dei messaggi

La funzionalità principale di un broker di messaggi come il bus di servizio è quella di accettare i messaggi in una coda o in un argomento e conservali rendendoli disponibili per un successivo recupero. Invio è il termine comunemente usato per il trasferimento di un messaggio in un broker di messaggi. Ricezione è il termine comunemente usato per il trasferimento di un messaggio in un client che esegue il recupero.

Quando un client invia un messaggio, in genere vuole sapere se il messaggio viene trasferito correttamente e accettato dal broker o se si è verificato un tipo di errore. Questo riconoscimento positivo o negativo risolve la comprensione sia del client che del broker sullo stato di trasferimento del messaggio. Pertanto, si parla di insediamento.

Analogamente, quando il broker trasferisce un messaggio a un client, il broker e il client vogliono stabilire se il messaggio è stato elaborato correttamente e può quindi essere rimosso o se il recapito o l'elaborazione del messaggio non è riuscito e pertanto il messaggio potrebbe dover essere recapitato nuovamente.

Finalizzazione delle operazioni di invio

Usando qualsiasi client API del bus di servizio supportato, le operazioni di invio nel bus di servizio vengono sempre finalizzate in modo esplicito, ovvero l'operazione API attende l'arrivo del risultato dell'accettazione dal bus di servizio e quindi completa l'operazione di invio.

Se il messaggio viene rifiutato da bus di servizio, il rifiuto contiene un indicatore di errore e un testo con un ID di rilevamento. Il rifiuto include anche informazioni relative al fatto che sia possibile o meno provare a eseguire di nuovo l'operazione con la possibilità di avere un esito positivo. Nel client queste informazioni vengono trasformate in un'eccezione, generata per il chiamante dell'operazione di invio. Se il messaggio viene accettato, l'operazione viene completata automaticamente.

Advanced Messaging Queuing Protocol (AMQP) è l'unico protocollo supportato per i client .NET Standard, Java, JavaScript, Python e Go. Per i client .NET Framework, è possibile usare bus di servizio Protocollo di messaggistica (SBMP) o AMQP. Quando si usa il protocollo AMQP, i trasferimenti di messaggi e gli insediamenti vengono distribuiti e asincroni. È consigliabile usare le varianti api del modello di programmazione asincrona.

Il 30 settembre 2026 verranno ritirate le librerie dell'SDK del bus di servizio di Azure WindowsAzure.ServiceBus, Microsoft.Azure.ServiceBus e com.microsoft.azure.servicebus, che non sono conformi alle linee guida di Azure SDK. Verrà terminato anche il supporto del protocollo SBMP, quindi non sarà più possibile usare questo protocollo dopo il 30 settembre 2026. Eseguire la migrazione alle librerie più recenti di Azure SDK, che offrono aggiornamenti critici della sicurezza e funzionalità migliorate, prima di tale data.

Anche se le librerie precedenti possono ancora essere usate oltre il 30 settembre 2026, non riceveranno più il supporto e gli aggiornamenti ufficiali da Microsoft. Per altre informazioni, vedere l'annuncio del ritiro del supporto.

Un mittente può inviare diversi messaggi in transito in rapida successione senza dover attendere il riconoscimento di ogni messaggio, come avverrebbe invece con il protocollo SBMP o HTTP 1.1. Le operazioni di invio asincrone vengono completate man mano che i relativi messaggi vengono accettati e archiviati, nelle entità partizionate o quando le operazioni di invio a entità diverse si sovrappongono. Il completamento può avvenire anche fuori dall'ordine di invio originale.

La strategia per gestire il risultato delle operazioni di invio può avere un impatto immediato e significativo sulle prestazioni dell'applicazione. Gli esempi in questa sezione sono scritti in C# e si applicano a futures Java, Java monos, JavaScript promises e concetti equivalenti in altri linguaggi.

Se l'applicazione genera picchi di messaggi, illustrati qui con un ciclo semplice, e si attende il completamento di ogni operazione di invio prima di inviare il messaggio successivo, le API sincrone o asincrone hanno un funzionamento simile e l'invio di 10 messaggi viene completato solo dopo 10 round trip completi sequenziali per la finalizzazione.

Con una distanza di latenza di round trip TCP (Transmission Control Protocol) di 70 millisecondi presunta da un sito locale a bus di servizio e dando solo 10 ms per bus di servizio accettare e archiviare ogni messaggio, il ciclo seguente richiede almeno 8 secondi, senza contare il tempo di trasferimento del payload o potenziali effetti di congestione della route:

for (int i = 0; i < 10; i++)
{
    // creating the message omitted for brevity
    await sender.SendMessageAsync(message);
}

Se l'applicazione avvia le 10 operazioni di invio asincrone in successione immediata e attende il rispettivo completamento separatamente, il tempo di round trip per tali 10 operazioni di invio si sovrappone. I 10 messaggi vengono trasferiti in successione immediata, potenzialmente anche condividendo frame TCP, e la durata complessiva del trasferimento dipende in gran parte dal tempo di rete necessario per trasferire i messaggi al broker.

Con gli stessi presupposti del ciclo precedente, il tempo totale di esecuzione sovrapposto per il ciclo seguente potrebbe rimanere ben inferiore a un secondo:

var tasks = new List<Task>();
for (int i = 0; i < 10; i++)
{
    tasks.Add(sender.SendMessageAsync(message));
}
await Task.WhenAll(tasks);

È importante notare che tutti i modelli di programmazione asincroni usano una forma di coda di lavoro nascosta basata sulla memoria che contiene operazioni in sospeso. Quando l'API di invio viene restituita, l'attività di invio viene accodata in tale coda di lavoro, ma il movimento del protocollo inizia solo una volta che è il turno dell'attività per l'esecuzione. Per il codice che tende a eseguire il push di burst di messaggi e dove l'affidabilità è un problema, è necessario prestare attenzione a non inserire troppi messaggi "in anteprima" contemporaneamente, perché tutti i messaggi inviati occupano memoria fino a quando non vengono messi in rete.

I semafori, come illustrato nel frammento di codice seguente in C#, sono oggetti di sincronizzazione che consentono, quando necessario, tale limitazione a livello di applicazione. Questo uso di un semaforo consente la presenza al massimo di 10 messaggi in corso contemporaneamente. Uno dei 10 blocchi semafori disponibili viene eseguito prima dell'invio e viene rilasciato al termine dell'invio. Il 11° passaggio attraverso il ciclo attende il completamento di almeno una delle operazioni di invio precedenti e quindi ne rende disponibile il blocco:

var semaphore = new SemaphoreSlim(10);

var tasks = new List<Task>();
for (int i = 0; i < 10; i++)
{
    await semaphore.WaitAsync();

    tasks.Add(sender.SendMessageAsync(message).ContinueWith((t)=>semaphore.Release()));
}
await Task.WhenAll(tasks);

Le applicazioni non devono mai avviare un'operazione di invio asincrona adottando l'approccio "fire-and-forget", ovvero senza recuperare il risultato dell'operazione. Ciò potrebbe caricare la coda di attività interna e invisibile fino a esaurire la memoria, impedendo all'applicazione di rilevare gli errori di invio:

for (int i = 0; i < 10; i++)
{
    sender.SendMessageAsync(message); // DON’T DO THIS
}

Con un client AMQP di basso livello, bus di servizio accetta anche trasferimenti "presettled". Un trasferimento preimpostato è un'operazione fire-and-forget per cui il risultato, in entrambi i casi, non viene segnalato al client e il messaggio viene considerato stabilito quando inviato. La mancanza di feedback al client significa anche che non sono disponibili dati interattivi per la diagnostica, il che significa che questa modalità non è idonea per la guida tramite supporto tecnico di Azure.

Finalizzazione delle operazioni di ricezione

Per le operazioni di ricezione, i client API del bus di servizio consentono due diverse modalità esplicite: ricezione ed eliminazione e blocco di visualizzazione.

ReceiveAndDelete

La modalità di ricezione ed eliminazione indica al broker di considerare tutti i messaggi inviati al client ricevente come finalizzati quando inviati. Ciò significa che il messaggio viene considerato utilizzato non appena il broker lo inserisce in rete. Se il trasferimento del messaggio non riesce, il messaggio viene perso.

Lo svantaggio di questa modalità è che il ricevitore non deve eseguire ulteriori azioni sul messaggio e non è rallentato anche attendendo il risultato della liquidazione. Se i dati contenuti nei singoli messaggi hanno un valore basso e/o sono significativi solo per un tempo molto breve, questa modalità è una scelta ragionevole.

PeekLock

La modalità blocco di visualizzazione indica al broker che il client ricevente richiede la finalizzazione esplicita dei messaggi ricevuti. Il messaggio viene reso disponibile per l'elaborazione del ricevitore, mentre viene mantenuto in un blocco esclusivo nel servizio in modo che altri ricevitori concorrenti non possano vederlo. La durata del blocco viene inizialmente definita a livello di coda o sottoscrizione e può essere estesa dal client proprietario del blocco, tramite l'operazione RenewMessageLockAsync . Per informazioni dettagliate sul rinnovo dei blocchi, vedere la sezione Rinnovare i blocchi in questo articolo.

Quando un messaggio è bloccato, gli altri client che ricevono dalla stessa coda o sottoscrizione possono accettare i blocchi e recuperare i successivi messaggi disponibili non attivamente bloccati. Quando il blocco su un messaggio viene rilasciato in modo esplicito o quando il blocco scade, il messaggio viene posizionato all'inizio dell'ordine di recupero per la fase di rollforward.

Quando il messaggio viene rilasciato ripetutamente dai ricevitori o lascia trascorrere il blocco per un numero definito di volte (numero massimo di recapito), il messaggio viene rimosso automaticamente dalla coda o dalla sottoscrizione e inserito nella coda di messaggi non recapitabili associati.

Il client ricevente avvia la liquidazione di un messaggio ricevuto con un riconoscimento positivo quando chiama l'API Completa per il messaggio. Indica al broker che il messaggio è stato elaborato correttamente e che il messaggio viene rimosso dalla coda o dalla sottoscrizione. Il broker risponde all'intenzione di finalizzazione del ricevitore indicando se la finalizzazione è stata possibile.

Quando il client di ricezione non riesce a elaborare un messaggio, ma vuole che il messaggio venga recapitato, può richiedere esplicitamente che il messaggio venga rilasciato e sbloccato immediatamente chiamando l'API Abandon per il messaggio oppure non può eseguire alcuna operazione e lasciare che il blocco sia trascorso.

Se un client di ricezione non riesce a elaborare un messaggio e sa che la ripetizione del messaggio e la ripetizione dell'operazione non sarà utile, può rifiutare il messaggio, che lo sposta nella coda dei messaggi non recapitabili chiamando l'API DeadLetter nel messaggio, che consente anche di impostare una proprietà personalizzata, incluso un codice motivo che può essere recuperato con il messaggio dalla coda di messaggi non recapitabili.

Nota

Esiste una sottoquery di messaggi non recapitabili per una coda o una sottoscrizione di argomenti solo quando è abilitata la funzionalità di messaggi non recapitabili per la coda o la sottoscrizione.

Un caso speciale di liquidazione è differimento, che viene discusso in un articolo separato.

Le Completeoperazioni , DeadLettero RenewLock potrebbero non riuscire a causa di problemi di rete, se il blocco bloccato è scaduto o esistono altre condizioni lato servizio che impediscono la liquidazione. In uno degli ultimi casi, il servizio invia un riconoscimento negativo (NAK) che genera un'eccezione nei client API. Se il motivo è una connessione di rete interrotta, il blocco viene eliminato perché bus di servizio non supporta il ripristino dei collegamenti AMQP esistenti in una connessione diversa.

Se Complete si verifica un errore, che si verifica in genere alla fine della gestione dei messaggi e in alcuni casi dopo alcuni minuti di lavoro di elaborazione, l'applicazione ricevente può decidere se mantenere lo stato del lavoro e ignorare lo stesso messaggio quando viene recapitato una seconda volta o se toss out il risultato di lavoro e riprova quando il messaggio viene recapitato di nuovo.

Il meccanismo tipico per l'identificazione di recapiti di messaggi duplicati consiste nel verificare il valore di message-id, che può e deve essere impostato dal mittente su un valore univoco, possibilmente allineato con un identificatore del processo di origine. Un'utilità di pianificazione del processo imposta probabilmente l'ID messaggio sull'identificatore del processo che sta tentando di assegnare a un ruolo di lavoro con il ruolo di lavoro specificato e il ruolo di lavoro ignorerà la seconda occorrenza dell'assegnazione del processo se tale processo è già stato eseguito.

Importante

È importante notare che il blocco che PeekLock o SessionLock acquisisce nel messaggio è volatile e può andare perso nelle condizioni seguenti

  • Aggiornamento del servizio
  • Aggiornamento del sistema operativo
  • Modifica delle proprietà nell'entità (Coda, Argomento, Sottoscrizione) mantenendo il blocco.

Quando il blocco viene perso, bus di servizio di Azure genererà un MessageLockLostException o SessionLockLostException, che verrà visualizzato nell'applicazione client. In questo caso, la logica di ripetizione dei tentativi predefinita del client deve essere avviata automaticamente e ripetere l'operazione.

Rinnovare i blocchi

Il valore predefinito per la durata del blocco è 1 minuto. È possibile specificare un valore diverso per la durata del blocco a livello di coda o sottoscrizione. Il client proprietario del blocco può rinnovare il blocco del messaggio usando metodi sull'oggetto ricevitore. È invece possibile usare la funzionalità di rinnovo automatico del blocco in cui è possibile specificare la durata per cui si vuole mantenere il blocco rinnovato.

È consigliabile impostare la durata del blocco su un valore superiore al tempo di elaborazione normale, quindi non è necessario rinnovare il blocco. Il valore massimo è di 5 minuti, quindi è necessario rinnovare il blocco se si vuole che sia più lungo. Avere una durata di blocco più lunga del necessario ha anche alcune implicazioni. Ad esempio, quando il client smette di funzionare, il messaggio diventerà nuovamente disponibile solo dopo il superamento della durata del blocco.

Passaggi successivi

  • Un caso speciale di liquidazione è differire. Per informazioni dettagliate, vedere rinvio del messaggio .
  • Per informazioni sui messaggi non recapitabili, vedere Code di messaggi non recapitabili.
  • Per altre informazioni generali sulla messaggistica bus di servizio, vedere bus di servizio code, argomenti e sottoscrizioni