🎉 Il Necronomicon è stato aggiornato alla versione 2.0.0 🎉
Code e semafori
Gestione delle code

Gestione delle Code

Libreria selezionata

La libreria che abbiamo scelto per la gestione delle code è la libreria BullMQ (opens in a new tab).

bullmq logo

BullMQ BullMQ (Bull Message Queues) è una libreria che sfrutta Redis per la

gestione delle code e dei job. È utile non solo per la gestione delle code, ma anche per la gestione delle risorse e per scambiare informazione in maniera performante all'interno dei microservizi

Installazione

Per installare BullMQ è necessario eseguire il seguente comando: bash npm install bullmq

Creazione di una coda

Per creare una coda è necessario eseguire il seguente codice:

import { Queue } from 'bullmq' const queue = new Queue('queue-name') // dove queue-name è il nome della coda
⚠️
Tieni a mente che ogni coda dovrà avere un nome diverso e che ogni worker deve avere come riferimento lo stesso nome per poter accedere ai job da completare

Creazione di un job

Per creare un job è necessario eseguire il seguente codice:

import { Queue } from 'bullmq'
 
const queue = new Queue('queue-name') // dove queue-name è il nome della coda
 
queue.add('job-name', { data: 'data' }) // dove job-name è il nome del job e data è il dato da passare al job

Ogni job può contenere un dato che verrà passato al worker che dovrà eseguire il job. Il dato può essere di qualsiasi tipo, ma è consigliato usare un oggetto.

Creazione di un worker

Per creare un worker è necessario eseguire il seguente codice:

import { Queue, Worker } from 'bullmq'
 
const queue = new Queue('queue-name') // dove queue-name è il nome della coda
 
const worker = new Worker(
  'queue-name', // dove queue-name è il nome della coda
  async (job) => {
    // dove job è il job da eseguire
    ...
  }
)

Il worker è una classe che permette di eseguire i job che vengono aggiunti alla coda. Il worker esegue il job in maniera asincrona e non blocca il thread principale.

Gestione delle connessioni

Sia il worker che la coda necessitano di una connessione a redis per poter funzionare e nel caso di BullMQ viene utilizzata la libreria redisio per la gestione delle connessioni.

I valori di default per la connessione sono: host: localhost e port: 6379

Per cambiare i valori di default è necessario eseguire il seguente codice:

import { Queue, Worker } from 'bullmq'
 
const connection = {
  host: 'yourhost.domain.com', // dove yourhost.domain.com è l'host di redis
  port: 9091 // dove 9091 è la porta di redis
}
 
const queue = new Queue('queue-name', { connection }) // dove queue-name è il nome della coda
 
const worker = new Worker(
  'queue-name', // dove queue-name è il nome della coda
  async (job) => {
    // dove job è il job da eseguire
    ...
  },
  { connection }
)

Ogni istanza di coda e worker creerà una connessione diversa, nel caso sia invece necessario utilizzare una stessa connessione basterà passare come valore del campo connection un'istanza di redisio:

import { Queue, Worker } from 'bullmq'
import Redis from 'ioredis'
 
const connection = new Redis({
  host: 'yourhost.domain.com', // dove yourhost.domain.com è l'host di redis
  port: 9091 // dove 9091 è la porta di redis
})
 
const queue = new Queue('queue-name', { connection }) // dove queue-name è il nome della coda
 
const worker = new Worker(
  'queue-name', // dove queue-name è il nome della coda
  async (job) => {
    // dove job è il job da eseguire
    ...
  },
  { connection }
)

In questo modo verrà utilizzata la stessa connessione per la coda e per il worker.

⚠️
Ricorda che il modo migliore di utilizzare Redis sarebbe generare una connessione per ogni coda o worker, la condivisione delle connessioni è da utilizzare solo nel momento in cui sia esplicitamente richiesto

Concorrenza

I worker di BullMQ possono essere eseguiti in parallelo, per fare ciò è necessario passare come terzo parametro del worker (quindi nell'oggetto relativo alle opzioni del worker) il campo concurrency con il valore del numero di worker che si vogliono eseguire in parallelo:

import { Queue, Worker } from 'bullmq'
 
const queue = new Queue('queue-name') // dove queue-name è il nome della coda
 
const worker = new Worker(
  'queue-name', // dove queue-name è il nome della coda
  async (job) => {
    // dove job è il job da eseguire
    ...
  },
  { concurrency: 5 } // dove 5 è il numero di worker che si vogliono eseguire in parallelo
)

In questo modo verranno eseguiti al massimo 5 worker in parallelo.

💡

Il valore di default per il campo concurrency è 1, quindi se non viene specificato verrà eseguito un solo worker alla volta.

⚠️

Ricorda che la concorrenza è possibile solo nel momento in cui il worker stia eseguendo delle funzioni asincrone poiché questo è l'unico modo con cui Node gestisce la concorrenza.

Per poter eseguire più worker in parallelo in altri casi, essi dovreanno essere eseguiti in processi diversi (opens in a new tab).

Esecuzione del worker

Il worker, di default, viene eseguito non appena viene creato. Per evitare che il worker venga eseguito subito è necessario passare come quarto parametro dell'oggetto relativo alle opzioni del worker il campo autorun con il valore false:

 
import { Queue, Worker } from 'bullmq'
 
const queue = new Queue('queue-name') // dove queue-name è il nome della coda
 
const worker = new Worker(
  'queue-name', // dove queue-name è il nome della coda
  async (job) => {
    // dove job è il job da eseguire
    ...
  },
  { autorun: false } // dove false indica che il worker non deve essere eseguito subito
)
 

In questo modo il worker non verrà eseguito subito, ma sarà necessario eseguire il metodo worker.run() per farlo partire.

💡

Il metodo worker.run() può essere eseguito in qualsiasi momento, anche dopo che il worker è stato fermato.

⚠️

Attenzione: il worker non verrà eseguito se non viene chiamato il metodo worker.run() e verrà fermato solo se viene chiamato il metodo worker.close()

Documentazione completa

Per una documentazione completa sui worker di BullMQ è possibile consultare il sito ufficiale qui (opens in a new tab).