I am trying to implement a background service so that there is less load on the API call. Background task will run to upload files to S3 and send email using nodemailer.
Asked
Active
Viewed 1,000 times
1 Answers
4
Following the loopback 4's design patterns you can create a service provider and inject it in your service or controller. Here is a very basic example with Bull.js:
import Bull, { Queue, Job } from "bull";
import {Provider, service} from "@loopback/core";
import {get} from "@loopback/rest";
export function audioProcessor(job: Job) {
console.log(
`Processing audio file: ${job.data.filename}`,
`Audio bitrate: ${job.data.bitrate}`
);
}
export class AudioQueueProvider implements Provider<Queue> {
async value() {
const queue = new Bull("AudioQueue", {
redis: { port: 6379, host: "127.0.0.1" }
});
queue.process(audioProcessor);
return queue;
}
}
export class AudioController {
constructor(
@service(AudioQueueProvider) public queue: Queue;
) {}
@get('/process-audio')
async addToQueue(): Promise<string> {
await this.queue.add(
{
filename: 'process_me.wav',
bitrate: 320,
}
);
return 'Audio file added to the AudioQueue for processing';
}
}
The RabbitMQ implementation should be similar (not tested):
import { Provider, service } from "@loopback/core";
import {get} from "@loopback/rest";
import amqp from "amqplib/callback_api";
export function audioProcessor(msg: any) {
console.log(
`Processing audio file: ${msg.content.filename}`,
`Audio bitrate: ${msg.content.bitrate}`
);
}
export class AudioQueueProvider implements Provider<any> {
async value() {
const CONN_URL = "amqp://localhost";
let ch = null;
const channelName = 'AudioQueue';
amqp.connect(CONN_URL, function (err, conn) {
conn.createChannel(function (err, channel) {
ch = channel;
});
});
ch.assertQueue(channelName, {
durable: false
});
ch.consume(channelName, audioProcessor, {
noAck: true
});
return ch;
}
}
export class AudioController {
constructor(
@service(AudioQueueProvider) public channel: any;
) {}
@get('/process-audio')
async addToQueue(): Promise<string> {
await this.channel.sendToQueue(
'AudioQueue',
{
filename: 'process_me.wav',
bitrate: 320,
}
);
return 'Audio file added to the AudioQueue for processing';
}
}

Svetljo
- 303
- 1
- 8
-
`@service(AudioQueueProvider) public queue: Queue` didn't work for me. I had to bind the AudioQueueProvider in application constructor and inject in the controller `@inject(QUEUE_SERVICE_BINDING_KEY) public queue: Queue` – Mohammad Quadri Sep 15 '20 at 14:50