Läsare som du hjälper till att stödja MUO. När du gör ett köp med hjälp av länkar på vår webbplats kan vi tjäna en affiliate-provision. Läs mer.

Som webbutvecklare är det avgörande att dina appar fungerar så snabbt de kan. Du bör bygga webbappar som svarar på förfrågningar på snabbast möjliga tid.

En av många tekniker som kan hjälpa dig är uppgiftsköer.

Så, vad är uppgiftskö, och hur kan du använda det för att optimera en Node.js-applikation?

Vad är Task Queuing?

Meddelandekö är ett sätt för asynkron kommunikation mellan två applikationer eller tjänster, vanligtvis kallad producent och konsument. Det är ett välkänt koncept som används i serverlösa arkitekturer och mikrotjänster.

Konceptet av uppgift eller jobbköa utnyttjar meddelandekö för att förbättra applikationsprestanda. Det abstraherar komplexiteten i att hantera meddelanden och gör det möjligt för dig att definiera funktioner för att hantera jobb eller uppgifter asynkront med hjälp av en kö, och därigenom minska hastigheten på minnesanvändning i vissa delar av en applikation.

instagram viewer

Det vanligaste exemplet på programvara för meddelandekö är RabbitMQ. Verktyg för uppgiftskö inkluderar Selleri och Bull. Du kan också konfigurera RabbitMQ att fungera som en uppgiftskö. Läs vidare för att lära dig om uppgiftskö i Node.js med Bull.

Vad är BullMQ?

BullMQ (Bull.js) är ett Node.js-bibliotek som används för att implementera köer i Node-applikationer. Bull är ett Redis-baserat system (du kanske är mer bekant med Redis som ett verktyg för snabb datalagring) och det är ett snabbt och pålitligt alternativ att överväga för uppgiftskö i Node.js.

Du kan använda Bull för många uppgifter som att implementera försenade jobb, schemalagda jobb, repeterbara jobb, prioriterade köer och många fler.

Så, hur kan du använda Bull och Redis för att köra Node.js-uppgifter asynkront?

Så här konfigurerar du Bull och Redis för uppgiftskö i Node.js

För att komma igång med uppgiftskö i Node.js med Bull behöver du Node.js och Redis installerade på din maskin. Du kan följa Redis labbguide för att installera Redis om du inte har den installerad.

Det första steget för att implementera Bull är att lägga till det i ditt projekts beroenden genom att köra npm installera bull eller garn tillsätt tjur i terminalen i ditt projekts mapp. Det finns flera sätt att initiera en kö i Bull som visas nedan:

konst Kö = behöva('tjur');

// olika sätt att initiera en kö
// - med redis URL-sträng
konst emailQueue = ny Kö("E-postkö", 'redis://127.0.0.1:6379');

// - med ett återuppkopplings- och köalternativ-objekt
konst videokö = ny Kö("Videokö", 'redis://127.0.0.1:6379', queueOptions);

// - utan redis-anslutning men med queueOption
konst docQueue = ny Kö("Dokumentkö", queueOptions);

// - utan redis-anslutning eller köalternativ
konst QueueClient = ny Kö("Min kö");

Dessa använder alla minimal konfiguration för Bull i Node.js. Alternativsobjektet stöder många egenskaper och du kan lära dig om dem i köalternativ i Bulls dokumentation.

Implementera en e-postuppgiftskö med BullMQ

För att implementera en kö för att skicka e-postmeddelanden kan du definiera din producentfunktion som lägger till e-postmeddelanden i e-postkön, och en konsumentfunktion för att hantera sändningen av e-postmeddelanden.

För det första kan du initiera din kö i en klass med hjälp av en Redis URL och några köalternativ som visas nedan.

// queueHandler.js
konst Kö = behöva('tjur');

// använd en riktig e-posthanterarmodul här - detta är bara ett exempel
konst emailHandler = behöva('./emailHandler.js');

// definiera konstanter, Redis URL och köalternativ
konst REDIS_URL = 'redis://127.0.0.1:6379';

konst queueOpts = {
// hastighetsbegränsare alternativ för att undvika överbelastning av kön
begränsare: {
// maximalt antal uppgifter som kön kan ta
max: 100,

// tid att vänta i millisekunder innan du accepterar nya jobb efter
// når gränsen
varaktighet: 10000
},
prefix: 'EMAIL-TASK', // ett prefix som ska läggas till alla könycklar
defaultJobOptions: { // standardalternativ för uppgifter i kön
Försök: 3, // standardantal gånger för att försöka igen en uppgift

// för att ta bort en uppgift från kön efter slutförande
removeOnComplete: Sann
}
};

klassEmailQueue{
konstruktör() {
detta.kö = ny Kö("E-postkö", REDIS_URL, queueOpts);
}
};

exporterastandard EmailQueue; // exportera klassen

Nu när du har initierat en kö kan du definiera din producentfunktion (med Bull's Lägg till() funktion) som en metod för EmailQueue klass för att lägga till e-postmeddelanden i uppgiftskön. Följande kodblock visar detta:

// queueHandler.js

klassEmailQueue{
konstruktör () {
// ...
}

// producentfunktion för att lägga till e-postmeddelanden i kön
asynkron addEmailToQueue (emailData) {
// lägg till uppgift med namnet 'email_notification' i kön
väntadetta.queue.add('email_notification', emailData);
trösta.logga("e-postmeddelandet har lagts till i kön...");
}
};

exporterastandard EmailQueue; // exportera klassen

Producentfunktionen är klar och du kan nu definiera en konsumentfunktion (med Bull's bearbeta() funktion) för att bearbeta alla e-postuppgifter i kön, dvs. ring funktionen för att skicka ett e-postmeddelande. Du bör definiera denna konsumentfunktion i klassens konstruktor.

// queueHandler.js
klassEmailQueue{
konstruktör () {
// ...

// konsumentfunktion som tar in det tilldelade namnet på uppgiften och
// en återuppringningsfunktion
detta.queue.process('email_notification', asynkron (e-postjobb, klart) => {
trösta.logga("bearbetar e-postaviseringsuppgift");
vänta emailHandler.sendEmail (emailJob); // skicka e-postmeddelandet
Gjort(); // gör klart uppgiften
})
}
// ...
};

exporterastandard EmailQueue; // exportera klassen

Ett jobb kan också ha alternativ för att definiera sitt beteende i kön eller hur konsumentfunktionen hanterar det. Du kan ta reda på mer om detta i jobbalternativ i Bulls dokumentation.

De emailJob argument är ett objekt som innehåller egenskaperna för uppgiften för kön att bearbeta. Den innehåller också de viktigaste uppgifterna som behövs för att skapa e-postmeddelandet. För enkel förståelse, den skicka epost() funktion skulle likna detta exempel:

// emailHandler.js
konst sendgridMail = behöva('@sendgrid/mail');

konst apiKey = process.env. SENDGRID_API_KEY

sendgridMail.setApiKey (apiKey); // ställ in e-posttransportörens säkerhetsuppgifter

konst skicka e-post = asynkron (emailJob) => {
Prova {
// extrahera e-postdata från jobbet
konst { namn, e-post } = emailJob.data;

konst meddelande = {
från: "[email protected]",
till: "[email protected]",
ämne: 'Hej! Välkommen',
text: `Hej ${name}, välkommen till MUO`
};

vänta sendgridMail.sendMail (meddelande); // skicka epost

// markera uppgiften som slutförd i kön
vänta emailJob.moveToCompleted('Gjort', Sann);
trösta.logga("E-postmeddelandet har skickats...");
} fånga (fel) {
// flytta uppgiften till misslyckade jobb
vänta emailJob.moveToFailed({ meddelande: 'uppgiftsbearbetningen misslyckades..' });
trösta.error (fel); // logga felet
}
}

exporterastandard skicka epost;

Nu när du har både producent- och konsumentfunktionerna definierade och klara att använda, kan du nu ringa din producentfunktion var som helst i din ansökan för att lägga till ett e-postmeddelande i kön för bearbetning.

Ett exempel på styrenhet skulle se ut så här:

// userController.js
konst EmailQueue = behöva('../handlers/queueHandler.js')

konst registrera dig = asynkron (req, res) => {
konst { namn, e-post, lösenord } = req.body;

// --
// en fråga för att lägga till den nya användaren till databasen...
// --

// lägg till i e-postkö
konst emailData = { namn, e-post };
vänta EmailQueue.addEmailToQueue (emailData);

res.status(200).json({
meddelande: "Registreringen lyckades, kolla din e-post"
})
}

Din queueHandler.js filen ska nu vara som följer:

// queueHandler.js
konst Kö = behöva('tjur');
konst emailHandler = behöva('../handlers/emailHandler.js');

konst REDIS_URL = 'redis://127.0.0.1:6379';

konst queueOpts = {
begränsare: {
max: 100,
varaktighet: 10000
},

prefix: 'EMAIL-TASK',

defaultJobOptions: {
Försök: 3,
removeOnComplete: Sann
}
};

klassEmailQueue{
konstruktör() {
detta.kö = ny Kö("E-postkö", REDIS_URL, queueOpts);

// konsument
detta.queue.process('email_notification', asynkron (e-postjobb, klart) => {
trösta.logga("bearbetar e-postaviseringsuppgift");
vänta emailHandler.sendEmail (emailJob);
Gjort();
})
}

// producent
asynkron addEmailToQueue (emailData) {
// lägg till uppgift med namnet 'email_notification' i kön
väntadetta.queue.add('email_notification', emailData);
trösta.logga("e-postmeddelandet har lagts till i kön...");
}
};

exporterastandard EmailQueue;

När du implementerar detta i ett Node.js REST API kommer du att märka en minskning av svarstiden för registreringsslutpunkten och snabbare leveranstider för e-post, jämfört med alternativet.

Uppgiftsköer gjorde det också möjligt för dig att hantera registrerings- och e-postfel oberoende av varandra.

Optimera applikationer med hjälp av uppgiftsköer

Meddelande- och uppgiftsköer är ett utmärkt sätt att förbättra applikationernas allmänna prestanda. De är också väldigt billiga och du kan använda dem i så många delar av en applikation som du behöver.

Även om den här handledningen använde e-postmeddelanden som ett exempelscenario för att hantera minneskrävande uppgifter med köer, finns det många andra fall där du kan tillämpa samma koncept. Dessa inkluderar tunga läs-/skrivoperationer, rendering av högkvalitativa bilder eller dokument och att skicka ut massmeddelanden.