I have a queue with 100 messages in. At some point, I'd like send a message but this message has a higher priority and should be treated first, before the 100 existing.
Is there a way to do this ?
Thanks,
Tried to set the but no more message arrive :
On the sender (Web API)
var bus = Bus.Factory.CreateUsingRabbitMq(sbc =>
sbc.Host("hostName", "host", h =>
{
h.Username("username");
h.Password("password);
})
);
Send the message
Uri uri = new Uri("queue:myQueue");
var endpoint = await bus.GetSendEndpoint(uri);
await endpoint.Send(request);
On the consumer (consoler app) :
static void Main(string[] args)
{
var busControl = Bus.Factory.CreateUsingRabbitMq(cfg =>
{
cfg.Host("localhost", "/", h =>
{
h.Username("guest");
h.Password("guest");
});
cfg.ReceiveEndpoint("myQueue", e =>
{
e.Handler<myType>(context =>
{
return Console.Out.WriteLineAsync($"{context.Message.Id}");
});
});
});
busControl.Start();
Console.WriteLine("Receive listening for messages");
Console.ReadLine();
busControl.Stop();
}
When configuring a receive endpoint, you can enable priority for that endpoint (queue):
configurator.ReceiveEndpoint("priority_input_queue", x =>
{
x.EnablePriority(4);
x.ConfigureConsumer(...);
});
This would configure the endpoint with maximum allowed priority of four (4).
Then, when sending/publishing a message, the priority can be specified:
await Bus.Publish(new Message(...), context =>
{
context.SetPriority(2);
});
If no value is specified, the default priority is used.
Related
I am using rabbitmq with nestjs. I need to replicate a message from one queue to another. I set up an exchange on rabbitmq to make it work. But how can I change the exchange of rabbitmq inside nestjs?
my api gateway
my current rabbitmq configuration inside nestjs:
constructor( ) {
this.rabbitmq = ClientProxyFactory.create({
transport: Transport.RMQ,
options: {
urls: [`amqp://${this.configService.get<string>('RABBITMQ_USER')}:${this.configService.get<string>('RABBITMQ_PASSWORD')}#${this.configService.get<string>('RABBITMQ_URL')}`],
queue: 'students'
}
})
}
createStudent(#Body() body: CreateStudentDto): Observable<any> {
return this.rabbitmq.send('createStudent', body)
}
my client
#MessagePattern('createStudent')
async createStudent(#Payload() student: Student, #Ctx() context: RmqContext) {
const channel = context.getChannelRef()
const originalMsg = context.getMessage()
try {
let response = await this.studentService.createStudent(student)
await channel.ack(originalMsg)
return response;
} catch(error) {
this.logger.log(`error: ${JSON.stringify(error.message)}`)
const filterAckError = ackErrors.filter(ackError => error.message.includes(ackError))
if (filterAckError.length > 0) {
await channel.ack(originalMsg)
}
}
}
I need the message to be sent to two queues.
I want to use mass transit redelivery for some exception .
according to mass transit document this must be worked :
consumer class :
public async Task Consume(ConsumeContext<SendEmailEvent> context)
{
try
{
...
}
catch (Exception ex)
{
throw new Exception($"email not sent to {email} errors : {ex.Message}", ex);
}
}
start up class :
Uri schedulerEndpoint = new Uri("rabbitmq://localhost/quartz");
services.AddMassTransit(x =>
{
x.AddConsumer<EmailConsumer>();
x.AddBus(provider => Bus.Factory.CreateUsingRabbitMq(cfg =>
{
cfg.UseHealthCheck(provider);
cfg.Host(new Uri("rabbitmq://localhost"), h =>
{
h.Username("guest");
h.Password("guest");
});
cfg.UseMessageScheduler(schedulerEndpoint);
cfg.ReceiveEndpoint("EmailQueue", ep =>
{
ep.UseScheduledRedelivery(r => r.Intervals(TimeSpan.FromMinutes(2), TimeSpan.FromMinutes(3), TimeSpan.FromMinutes(30)));
ep.UseMessageRetry(r => r.Immediate(5));
ep.ConfigureConsumer<EmailConsumer>(provider);
});
}));
});
services.AddMassTransitHostedService();
after 5 Immediate failed attempted (I change consumer implementation to catch error every time) it won't send any request after 2 or 3 mins (Intervals config time) also it does not create 'quartz' Queue .
How can I solve this ?
I have about 100 different types of messages and I'd like to know the correct way to consume them in RabbitMq.
I have 2 solutions and I don't know which one is the best way.
1: Implement 100 consumers for 100 different types of messages.
2: Implement 1 consumer and process the messages by for example switch case or etc.
In your opinion what's the best way?
If you are going to be calling 100 different messaging services then you will need to set up 100 different consumers BUT use only on rabbitmq connection
Here is how I implemented my rabbitmq consumer
module.exports.start = async () => {
try{
const queue1 = 'email';
const connection = await amqplib.connect(process.env.QUEUE_SERVICE);
const channel = await connection.createChannel();
await channel.assertQueue(queue1, { durable: true });
await channel.prefetch(1);
console.log('Listening for emails...');
channel.consume(queue1, async (msg) => {
if (msg !== null) {
winston.info(`Got message ${msg.content.toString()}`);
const queueMessage = JSON.parse(msg.content.toString());
Emails.Mailer(queueMessage)
.then(() => {
channel.ack(msg)
})
.catch(err=> err);
}
});
const queue2 = 'sms';
await channel.assertQueue(queue2, { durable: true });
await channel.prefetch(1);
console.log('Listening for SMS...');
channel.consume(queue2, async (msg) => {
if (msg !== null) {
const queueMessage = JSON.parse(msg.content.toString());
Sms.sendPaymentSms(queueMessage).then(() => channel.ack(msg));
}
});
} catch (error) {
return error
}
};
Another thing you can do to maintain code readability is to modularize the various services you want to call and call them in your consumer using conditionals or strategy design pattern.
I have a question about MassTransit configuration.
There is a Main application and Microservice.
For example, the Main application sends a commands to the microservice(consumer) to write off funds from the account.
Configuration in the Main application:
var rabbitHost = new Uri("rabbitmq://localhost/app");
services.AddMassTransit(x => {
x.AddBus(provider => Bus.Factory.CreateUsingRabbitMq(cfg => {
var host = cfg.Host(rabbitHost, hostConfigurator => {
hostConfigurator.Username("user");
hostConfigurator.Password("password");
});
}));
});
EndpointConvention.Map<WithdrawFunds>(new Uri(rabbitHost + "/test-queue"));
Microservice configuration:
var rabbitHost = new Uri("rabbitmq://localhost/app");
services.AddMassTransit(x => {
x.AddBus(provider => Bus.Factory.CreateUsingRabbitMq(cfg => {
var host = cfg.Host(rabbitHost, hostConfigurator => {
hostConfigurator.Username("username");
hostConfigurator.Password("password");
});
cfg.ReceiveEndpoint(host, "test-queue", ep => {
ep.Consumer<WithdrawFundsConsumer>();
});
}));
});
Command executed in Main application like:
await _sendEndpointProvider.Send<WithdrawFunds>(new {
Amount = 100,
AccountId = "someId"
});
MassTransit creates a "test-queue" queue and if both applications are running, then the interaction works successfully. But if I stop the microservice, then a
"test-queue_skipped" queue is created in which the missed messages fall. However, if I start the Microservice, it will not receive missed messages.
How can I configure MassTransit so that "_skipped" is not created, and messages are waiting for the consumer to appear?
About
I am learning Vue.js with Laravel. Presently, practicing on sending real time text messages between 2 users.
Below code sends message to another user
var url = "http://localhost:6001/apps/My_appId/events?auth_key=My_Key";
var socketId = Echo.socketId();
var request = {
"channel": "private-Send-Message-Channel.2",
"name": "MessengerEvent",
"data": {
"msg": message
},
"socket_id": socketId
};
axios.post(url,
JSON.stringify(request))
.then((response) => {
//Success callback
}
);
Receive the message
window.Echo.private('Send-Message-Channel.2')
.on('MessengerEvent', (e) => {
//Receive the message
}
);
Question: Is there any callback for on leave, on join , on typing, total users?
You need to user a presence channel. As described these channels are also private:
All presence channels are also private channels
You can set up a presence channel by using .join.
Echo.join(`chat.${roomId}`)
.here((users) => {
//
})
.joining((user) => {
console.log(user.name);
})
.leaving((user) => {
console.log(user.name);
});
There you have access to the callback that you are looking for.