Come usare le code del bus di servizio con Node.js

Questo articolo illustra come usare le code del bus di servizio con Node.js. Gli esempi sono scritti in JavaScript e utilizzano il modulo Node.js di Azure. Gli scenari presentati includono la creazione di code, l'invio e la ricezione di messaggi e l'eliminazione di code. Per altre informazioni sulle code, vedere la sezione Passaggi successivi .

Informazioni sulle code del bus di servizio

Le code del bus di servizio supportano un modello di comunicazione con messaggistica negoziata . Quando si usano le code, i componenti di un'applicazione distribuita non comunicano direttamente l'uno con l'altro, ma scambiano messaggi tramite una coda, che agisce da intermediario (broker). Un producer di messaggi (mittente) invia un messaggio alla coda e quindi prosegue con la relativa elaborazione. In modo asincrono, il consumer di messaggi (ricevitore) recupera il messaggio dalla coda e lo elabora. Il producer non deve attendere la risposta del consumer per continuare a elaborare e inviare ulteriori messaggi. Le code consentono un recapito dei messaggi di tipo FIFO (First In, First Out) a uno o più consumer concorrenti. In base a questo metodo, in genere i messaggi vengono ricevuti ed elaborati nell'ordine temporale in cui sono stati aggiunti alla coda e ogni messaggio viene ricevuto ed elaborato da un solo consumer.

Concetti relativi alle code

Le code del bus di servizio sono una tecnologia di carattere generale che può essere usata in numerosi scenari:

  • Comunicazione tra ruoli Web e di lavoro in un'applicazione Azure multilivello.
  • Comunicazione tra app locali e app ospitate in Azure in una soluzione ibrida.
  • Comunicazione tra componenti di un'applicazione distribuita in esecuzione in locale in organizzazioni diverse o in reparti diversi della stessa organizzazione.

L'uso delle code consente la scalabilità delle applicazioni e garantisce maggiore resilienza all'architettura.

Per iniziare a usare le entità di messaggistica del bus di servizio in Azure, prima di tutto è necessario creare uno spazio dei nomi con un nome univoco in Azure. Uno spazio dei nomi fornisce un contenitore di ambito per fare riferimento alle risorse del bus di servizio all'interno dell'applicazione.

Per creare uno spazio dei nomi:

  1. Accedere al portale di Azure.
  2. Nel riquadro di spostamento sinistro del portale fare clic su Nuovo, quindi su Enterprise Integration e infine su Bus di servizio.
  3. Nella finestra di dialogo Crea spazio dei nomi immettere un nome per lo spazio dei nomi. Verrà effettuato immediatamente un controllo sulla disponibilità del nome.
  4. Dopo aver verificato che il nome dello spazio dei nomi sia disponibile, scegliere il piano tariffario, ovvero Basic, Standard o Premium.
  5. Nel campo Sottoscrizione scegliere una sottoscrizione di Azure in cui creare lo spazio dei nomi.
  6. Nel campo Gruppo di risorse scegliere un gruppo di risorse esistente nel quale risiederà lo spazio dei nomi oppure crearne uno nuovo.
  7. In Localitàscegliere il paese o l'area in cui deve essere ospitato lo spazio dei nomi.

    Crea spazio dei nomi

  8. Fare clic su Crea. A questo punto, lo spazio dei nomi verrà creato e abilitato nel sistema. Potrebbero essere necessari alcuni minuti per consentire al sistema di effettuare il provisioning delle risorse per lo spazio dei nomi creato.

Ottenere le credenziali di gestione

Con la creazione di un nuovo spazio dei nomi verrà generata automaticamente una regola di firma di accesso condiviso iniziale con una coppia di chiavi primaria e secondaria associata che concede il controllo completo di tutti gli aspetti dello spazio dei nomi. Vedere Autenticazione e autorizzazione del bus di servizio per informazioni su come creare altre regole con diritti più limitati per mittenti e destinatari normali. Per copiare la regola iniziale seguire questa procedura:

  1. Nell'elenco degli spazi dei nomi fare clic sul nome dello spazio dei nomi appena creato.
  2. Nel pannello dello spazio dei nomi fare clic su Criteri di accesso condivisi.
  3. Nel pannello Criteri di accesso condivisi fare clic su RootManageSharedAccessKey.

    connection-info

  4. Nel pannello Criteri: RootManageSharedAccessKey fare clic sul pulsante Copia accanto a Stringa di connessione - chiave primaria per copiare la stringa di connessione negli Appunti e usarla in un secondo momento. Incollare questo valore nel Blocco note o in un'altra posizione temporanea.

    connection-string

  5. Ripetere il passaggio precedente e copiare e incollare il valore della chiave primaria in un percorso temporaneo per usarlo in seguito.

Creare un'applicazione Node.js

Creare un'applicazione Node.js vuota. Per istruzioni su come creare un'applicazione Node.js, vedere Creare un'app Web Node.js nel servizio app di Azure oppure Creazione e distribuzione di un'applicazione Node.js a un servizio cloud di Azure con Windows PowerShell.

Configurare l'applicazione per l'uso del bus di servizio

Per usare il bus di servizio di Azure, scaricare e usare il pacchetto Azure Node.js che include un set di librerie di riferimento che comunicano con i servizi REST del bus di servizio.

Usare Node Package Manager (NPM) per ottenere il pacchetto

  1. Usare la finestra di comando Windows PowerShell per Node.js per passare alla cartella c:\node\sbqueues\WebRole1 in cui è stata creata l'applicazione di esempio.
  2. Digitare npm install azure nella finestra di comando, che dovrebbe restituire un output simile al seguente:

    azure@0.7.5 node_modules\azure
        ├── dateformat@1.0.2-1.2.3
        ├── xmlbuilder@0.4.2
        ├── node-uuid@1.2.0
        ├── mime@1.2.9
        ├── underscore@1.4.4
        ├── validator@1.1.1
        ├── tunnel@0.0.2
        ├── wns@0.5.3
        ├── xml2js@0.2.7 (sax@0.5.2)
        └── request@2.21.0 (json-stringify-safe@4.0.0, forever-agent@0.5.0, aws-sign@0.3.0, tunnel-agent@0.3.0, oauth-sign@0.3.0, qs@0.6.5, cookie-jar@0.3.0, node-uuid@1.4.0, http-signature@0.9.11, form-data@0.0.8, hawk@0.13.1)
    
  3. È possibile eseguire manualmente il comando ls per verificare che sia stata creata una cartella node_modules. All'interno di tale cartella individuare il pacchetto azure, che contiene le librerie necessarie per accedere alle code del bus di servizio.

Importare il modulo

Usando il Blocco note o un altro editor di testo, aggiungere quanto segue alla parte superiore del file server.js dell'applicazione:

var azure = require('azure');

Configurare una connessione del bus di servizio di Azure

Il modulo di Azure legge la variabile di ambiente AZURE_SERVICEBUS_CONNECTION_STRING per ottenere le informazioni necessarie per la connessione al bus di servizio. Se questa variabile di ambiente non è impostata, è necessario specificare le informazioni relative all'account durante la chiamata di createServiceBusService.

Per un esempio di impostazione delle variabili di ambiente in un file di configurazione per un servizio cloud di Azure, vedere Creazione di un'applicazione Web Node.js con Archiviazione.

Per un esempio di impostazione delle variabili di ambiente nel portale di Azure per un sito Web di Azure, vedere Node.js Web Application with Storage (Applicazione Web Node.js con Archiviazione di Azure).

Creare una coda

L'oggetto ServiceBusService consente di usare le code del bus di servizio. Il codice seguente consente di creare un oggetto ServiceBusService. Aggiungerlo nella parte superiore del file server.js dopo l'istruzione per importare il modulo Azure:

var serviceBusService = azure.createServiceBusService();

Chiamando createQueueIfNotExists nell'oggetto ServiceBusService, viene restituita la coda specificata, se esistente, oppure viene creata una nuova coda con il nome specificato. Il codice seguente usa createQueueIfNotExists per connettersi alla coda denominata myqueue o crearla:

serviceBusService.createQueueIfNotExists('myqueue', function(error){
    if(!error){
        // Queue exists
    }
});

Il metodo createServiceBusService supporta anche opzioni aggiuntive che consentono di eseguire l'override delle impostazioni predefinite delle code, come la durata (TTL) dei messaggi o le dimensioni massime della coda. Il seguente esempio illustra come impostare la dimensione massima della coda su 5 GB e una durata (TTL) di 1 minuto:

var queueOptions = {
      MaxSizeInMegabytes: '5120',
      DefaultMessageTimeToLive: 'PT1M'
    };

serviceBusService.createQueueIfNotExists('myqueue', queueOptions, function(error){
    if(!error){
        // Queue exists
    }
});

Filtri

Le operazioni di filtro facoltative possono essere applicate alle operazioni eseguite usando ServiceBusService. Le operazioni di filtro possono includere la registrazione, la ripetizione automatica dei tentativi e così via. I filtri sono oggetti che implementano un metodo con la firma:

function handle (requestOptions, next)

Dopo avere eseguito la pre-elaborazione sulle opzioni della richiesta, il metodo deve chiamare next passando un callback con la seguente firma:

function (returnObject, finalCallback, next)

Dopo l'elaborazione di returnObject (ossia della risposta della richiesta al server), questo callback deve richiamare next, se esistente, per continuare a elaborare altri filtri oppure richiamare semplicemente finalCallback per terminare la chiamata al servizio.

In Azure SDK per Node.js sono inclusi due filtri che implementano la logica di ripetizione dei tentativi, ExponentialRetryPolicyFilter e LinearRetryPolicyFilter. Il codice seguente crea un oggetto ServiceBusService che usa ExponentialRetryPolicyFilter:

var retryOperations = new azure.ExponentialRetryPolicyFilter();
var serviceBusService = azure.createServiceBusService().withFilter(retryOperations);

Inviare messaggi a una coda

Per inviare un messaggio a una coda del bus di servizio, l'applicazione chiama il metodo sendQueueMessage per l'oggetto ServiceBusService. I messaggi inviati e ricevuti dalle code del bus di servizio sono oggetti BrokeredMessage e includono un set di proprietà standard, ad esempio Label e TimeToLive, un dizionario usato per contenere le proprietà personalizzate specifiche dell'applicazione e un corpo di dati arbitrari dell'applicazione. Un'applicazione può impostare il corpo del messaggio passando una stringa come messaggio. Le proprietà standard necessarie vengono popolate con i valori predefiniti.

L'esempio seguente illustra come inviare un messaggio di prova alla coda denominata myqueue usando sendQueueMessage:

var message = {
    body: 'Test message',
    customProperties: {
        testproperty: 'TestValue'
    }};
serviceBusService.sendQueueMessage('myqueue', message, function(error){
    if(!error){
        // message sent
    }
});

Le code del bus di servizio supportano messaggi di dimensioni fino a 256 KB nel livello Standard e fino a 1 MB nel livello Premium. Le dimensioni massime dell'intestazione, che include le proprietà standard e personalizzate dell'applicazione, non possono superare 64 KB. Non esiste alcun limite al numero di messaggi mantenuti in una coda, mentre è prevista una limitazione alla dimensione totale dei messaggi di una coda. Questa dimensione della coda viene definita al momento della creazione, con un limite massimo di 5 GB. Per altre informazioni sulle quote, vedere Quote del bus di servizio.

Ricevere messaggi da una coda

I messaggi vengono ricevuti da una coda usando il metodo receiveQueueMessage nell'oggetto ServiceBusService. Per impostazione predefinita, i messaggi vengono eliminati dalla coda non appena vengono letti. È tuttavia possibile leggere (visualizzare) e bloccare il messaggio senza eliminarlo dalla coda impostando il parametro facoltativo isPeekLock su true.

Il comportamento predefinito di lettura ed eliminazione del messaggio nell'ambito dell'operazione di ricezione costituisce il modello più semplice ed è adatto per scenari in cui un'applicazione può tollerare la mancata elaborazione di un messaggio in caso di errore. Per comprendere meglio questo meccanismo, si consideri uno scenario in cui il consumer invia la richiesta di ricezione e viene arrestato in modo anomalo prima dell'elaborazione. Poiché il bus di servizio contrassegna il messaggio come utilizzato, quando l'applicazione viene riavviata e inizia a utilizzare nuovamente i messaggi, il messaggio utilizzato prima dell'arresto anomalo risulterà perso.

Se il parametro isPeekLock è impostato su true, l'operazione di ricezione viene suddivisa in due fasi, in modo da consentire il supporto di applicazioni che non possono tollerare messaggi mancanti. Quando il bus di servizio riceve una richiesta, individua il messaggio successivo da usare, lo blocca per impedirne la ricezione da parte di altri consumer e quindi lo restituisce all'applicazione. Dopo aver elaborato il messaggio o averlo archiviato in modo affidabile per una successiva elaborazione, l'applicazione esegue la seconda fase del processo di ricezione chiamando il metodo deleteMessage e specificando il messaggio da eliminare come parametro. Il metodo deleteMessage contrassegna il messaggio come utilizzato e lo rimuove dalla coda.

L'esempio seguente illustra come ricevere ed elaborare messaggi usando receiveQueueMessage. L'esempio prima di tutto riceve ed elimina un messaggio, quindi riceve un messaggio con isPeekLock impostato su true e infine elimina il messaggio con deleteMessage:

serviceBusService.receiveQueueMessage('myqueue', function(error, receivedMessage){
    if(!error){
        // Message received and deleted
    }
});
serviceBusService.receiveQueueMessage('myqueue', { isPeekLock: true }, function(error, lockedMessage){
    if(!error){
        // Message received and locked
        serviceBusService.deleteMessage(lockedMessage, function (deleteError){
            if(!deleteError){
                // Message deleted
            }
        });
    }
});

Come gestire arresti anomali e messaggi illeggibili dell'applicazione

Il bus di servizio fornisce funzionalità per il ripristino gestito automaticamente in caso di errori nell'applicazione o di problemi di elaborazione di un messaggio. Se un'applicazione ricevente non riesce a elaborare il messaggio per qualsiasi motivo, può chiamare il metodo unlockMessage nell'oggetto ServiceBusService. In questo modo, il bus di servizio sbloccherà il messaggio nella coda rendendolo nuovamente disponibile per la ricezione da parte della stessa o da un'altra applicazione consumer.

Al messaggio bloccato nella coda è inoltre associato un timeout. Se l'applicazione non riesce a elaborare il messaggio prima della scadenza del timeout, ad esempio a causa di un arresto anomalo, il bus di servizio sbloccherà automaticamente il messaggio rendendolo nuovamente disponibile per la ricezione.

In caso di arresto anomalo dell'applicazione dopo l'elaborazione del messaggio ma prima della chiamata del metodo deleteMessage, il messaggio verrà nuovamente recapitato all'applicazione al riavvio. Questo processo di elaborazione viene spesso definito di tipo At-Least-Once, per indicare che ogni messaggio verrà elaborato almeno una volta ma che in determinate situazioni potrà essere recapitato una seconda volta. Se lo scenario non tollera la doppia elaborazione, gli sviluppatori dovranno aggiungere logica aggiuntiva all'applicazione per gestire il secondo recapito del messaggio. A tale scopo viene spesso usata la proprietà MessageId del messaggio, che rimane costante in tutti i tentativi di recapito.

Passaggi successivi

Per altre informazioni sulle code, vedere le risorse seguenti.