Dart and RabbitMQ bind exchange - rabbitmq

I use STOMP package, and I wrote a test:
test('can subscribe and send events to mq server', () async {
StompClient client2 = await serverClient.connect(mqIp,
port: mqPort, login: login, passcode: password);
client2.sendJson('Domain changed', {'a':'b'});
client2.disconnect();
StreamController controller = new StreamController();
Stream<String> stream = controller.stream.asBroadcastStream();
StompClient client1 = await serverClient.connect(mqIp,
port: mqPort, login: login, passcode: password);
client1.subscribeString("Entity changed", 'Domain changed',
(Map<String, String> headers, String message) {
controller.add(message);
}, ack: AUTO);
await for (String message in stream) {
String expectedEntity =
'{\"a\":\"b\"}';
expect(message, equals(expectedEntity));
break;
}
client1.unsubscribe("Entity changed");
client1.disconnect();
}, timeout: new Timeout(new Duration(seconds: 6)));
When I run pub run test I get Test timed out.
In RabbitMQ Managment in bindings section I get: (Default exchange binding) and zero in total messages:
Is it possible to send and recive messages in one channel?
If I use client1.subscribeString(ack: CLIENT,...) in RabbitMQ Managment I get one message "In memory" but test still Test timed out and I can't get message from mq.
Maybe I must set up amq.fanout exchange, but how I can do this?

Best choice for use RabbitMq with dart: mqtt package

Related

.Net Core 3.1 SignalR Client Starts and Stops receiving messages at specific intervals

Does an Azure VM throttle SignalR messages being sent? Running locally, the client receives every message, but when hosted on the VM, clients only receive messages 30% of the time!?!?
This question is about Microsoft.AspNet.SignalR nuget package for SignalR in .Net Core 3.1 API back end, with a VueJS SPA front-end, all being hosted on an Azure Windows Server 2016 VM using IIS 10.
On my local machine, SignalR works perfectly. Messages get sent/received all the time, instantaneously. Then I publish to the VM, and when (IF) the WebSocket connection is successful, the client can only receive messages for the first 5 or so seconds at most, then stops receiving messages.
I've set up a dummy page that sends a message to my API, which then sends said message back down to all connections. It's a simple input form and "Send" button. After the few seconds of submitting and receiving messages, I need to rapidly submit (even hold down the "enter" button to submit) the form and send what should be a constant stream of messages back, until, low and behold, several seconds later messages begin to be received again, but only for a few seconds.
I've actually held down the submit button for constant stream and timed how long it takes to start getting messages, then again how long it takes to stop receiving. My small sample shows ~30 messages get received, then skips (does not receive) the next ~70 messages until another ~30 messages come in .. then the pattern persists, no messages for several seconds, then (~30) messages for a few seconds.
Production Environment Continuously Sending 1000 messages:
Same Test in Local Environment Sending 1000 messages:
If I stop the test, not matter how long I wait, when I hold the enter button (repeated submit), it takes a few seconds to get back into the 3 second/2 second pattern. It's almost as if I need to keep pressuring the server to send the message back to the client, otherwise the server gets lazy and doesn't do any work at all. If I slow play the message submits, it's rare that the client receives any messages at all. I really need to persistently and quickly send messages in order to start receiving them again.
FYI, during the time that I am holding down submit, or rapidly submitting, I receive no errors for API calls (initiating messages) and no errors for Socket Connection or receiving messages. All the while, when client side SignalR log level is set to Trace, I see ping requests being sent and received successfully every 10 seconds.
Here is the Socket Config in .Net:
services.AddSignalR()
.AddHubOptions<StreamHub>(hubOptions => {
hubOptions.EnableDetailedErrors = true;
hubOptions.ClientTimeoutInterval = TimeSpan.FromHours(24);
hubOptions.HandshakeTimeout = TimeSpan.FromHours(24);
hubOptions.KeepAliveInterval = TimeSpan.FromSeconds(15);
hubOptions.MaximumReceiveMessageSize = 1000000;
})
.AddJsonProtocol(options =>
{
options.PayloadSerializerOptions.PropertyNamingPolicy = null;
});
// Adding Authentication
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
// Adding Jwt Bearer
.AddJwtBearer(options =>
{
options.SaveToken = true;
options.RequireHttpsMetadata = false;
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,
ValidateAudience = true,
ValidAudience = Configuration["JWT:ValidAudience"],
ValidIssuer = Configuration["JWT:ValidIssuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JWT:Secret"])),
ClockSkew = TimeSpan.Zero
};
// Sending the access token in the query string is required due to
// a limitation in Browser APIs. We restrict it to only calls to the
// SignalR hub in this code.
// See https://learn.microsoft.com/aspnet/core/signalr/security#access-token-logging
// for more information about security considerations when using
// the query string to transmit the access token.
options.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
var accessToken = context.Request.Query["access_token"];
// If the request is for our hub...
var path = context.HttpContext.Request.Path;
if (!string.IsNullOrEmpty(accessToken) && (path.StartsWithSegments("/v1/stream")))
{
// Read the token out of the query string
context.Token = accessToken;
}
return Task.CompletedTask;
}
};
});
I use this endpoint to send back messages:
[HttpPost]
[Route("bitcoin")]
public async Task<IActionResult> SendBitcoin([FromBody] BitCoin bitcoin)
{
await this._hubContext.Clients.All.SendAsync("BitCoin", bitcoin.message);
return Ok(bitcoin.message);
}
Here is the Socket Connection in JS and the button click to call message API:
this.connection = new signalR.HubConnectionBuilder()
.configureLogging(process.env.NODE_ENV.toLowerCase() == 'development' ? signalR.LogLevel.None : signalR.LogLevel.None)
.withUrl(process.env.VUE_APP_STREAM_ROOT, { accessTokenFactory: () => this.$store.state.auth.token })
.withAutomaticReconnect({
nextRetryDelayInMilliseconds: retryContext => {
if(retryContext.retryReason && retryContext.retryReason.statusCode == 401) {
return null
}
else if (retryContext.elapsedMilliseconds < 3600000) {
// If we've been reconnecting for less than 60 minutes so far,
// wait between 0 and 10 seconds before the next reconnect attempt.
return Math.random() * 10000;
} else {
// If we've been reconnecting for more than 60 seconds so far, stop reconnecting.
return null;
}
}
})
.build()
// connection timeout of 10 minutes
this.connection.serverTimeoutInMilliseconds = 1000 * 60 * 10
this.connection.reconnectedCallbacks.push(() => {
let alert = {
show: true,
text: 'Data connection re-established!',
variant: 'success',
isConnected: true,
}
this.$store.commit(CONNECTION_ALERT, alert)
setTimeout(() => {
this.$_closeConnectionAlert()
}, this.$_appMessageTimeout)
// this.joinStreamGroup('event-'+this.event.eventId)
})
this.connection.onreconnecting((err) => {
if(!!err) {
console.log('reconnecting:')
this.startStream()
}
})
this.connection.start()
.then((response) => {
this.startStream()
})
.catch((err) => {
});
startStream() {
// ---------
// Call client methods from hub
// ---------
if(this.connection.connectionState.toLowerCase() == 'connected') {
this.connection.methods.bitcoin = []
this.connection.on("BitCoin", (data) => {
console.log('messageReceived:', data)
})
}
}
buttonClick() {
this.$_apiCall({url: 'bitcoin', method: 'POST', data: {message:this.message}})
.then(response => {
// console.log('message', response.data)
})
}
For the case when the Socket Connection fails:
On page refresh, sometimes the WebSocket Connection fails, but there are multiple calls to the Socket endpoint that are almost identical, where one returns 404 and another returns a 200 result
Failed Request
This is the request that failed, the only difference to the request that succeeded (below) is the content-length in the Response Headers (highlighted). The Request Headers are identical:
Successful request to Socket Endpoint
Identical Request Headers
What could be so different about the configuration on my local machine vs. the configuration on my Azure VM? Why would the client stop and start receiving messages like this? Might it be the configuration on my VM? Are the messages getting blocked somehow? I've exhausted myself trying to figure this out!!
Update:
KeepAlive messages are being sent correctly, but the continuous stream of messages sent (expecting received) only works periodically.
Here we see that the KeepAlive messages are being sent and received every 15 seconds, as expected.

I have created a pub/sub model using #nestjs-plus/rabbitmq library but not being able to send acknowledgement from subscriber to publisher

I have used #RabbitSubscribe() decorator for subscription and AmqpConnection.publish() for publisher and Pub/Sub is working properly. But I want acknowledgement back from subscriber to publisher when message will be delivered.
I expect the publisher should receive acknowledgement from subscriber.
To get an answer, you need to use RPC Handlers.
Send message:
const requestOptions: RequestOptions = {
payload: {foo: 'bar'},
exchange: 'exchange1',
routingKey: 'rpc-route'
};
const result = await this.amqpConnection.request(requestOptions);
Message handling and response:
#RabbitRPC({
exchange: 'exchange1',
routingKey: 'rpc-route',
queue: 'rpc-queue'
})
public async rpcHandler(msg: {}) {
return {
response: 42
};
}

Rabbitmq doesn't persistent a message in exchange if there is no subscriber?

I have the following publisher and subscriber:
// publisher.js
var amqp = require('amqplib/callback_api');
amqp.connect('amqp://localhost', function(err, conn) {
conn.createChannel(function(err, ch) {
var ex = 'logs';
var msg = process.argv.slice(2).join(' ') || 'Hello World!';
ch.assertExchange(ex, 'fanout', {durable: true});
ch.publish(ex, '', new Buffer(msg));
console.log(" [x] Sent %s", msg);
});
setTimeout(function() { conn.close(); process.exit(0) }, 500);
});
//subscriber.js
var amqp = require('amqplib/callback_api');
amqp.connect('amqp://localhost', function(err, conn) {
conn.createChannel(function(err, ch) {
var ex = 'logs';
ch.assertExchange(ex, 'fanout', {durable: true});
ch.assertQueue('', {exclusive: true}, function(err, q) {
console.log(" [*] Waiting for messages in %s. To exit press CTRL+C", q.queue);
ch.bindQueue(q.queue, ex, '');
ch.consume(q.queue, function(msg) {
if(msg.content) {
console.log(" [x] %s", msg.content.toString());
}
}, {noAck: true});
});
});
});
If I run the publisher.js to publish two messages, and then run the subscriber.js, I would expect the subscriber to print two messages that I published in the past, but actually subscriber doesn't receive any messages.
How to let RabbitMQ persist the published messages that allow any subscriber to consume from the beginning or wherever they consumed last time?
If RabbitMQ can't route a message to a queue, the message is dropped.
Since you run your publisher code prior to your subscriber code, there is no queue bound to your exchange and, thus, nowhere to route the message.
You need to either run your subscriber code before your publisher, or you have to have your publisher or some other process create and bind a named queue to your exchange. Then, your subscriber will use that queue.
NOTE: the RabbitMQ team monitors the rabbitmq-users mailing list and only sometimes answers questions on StackOverflow.

How to authenticate rabbitmq in nodejs?

Error: Handshake terminated by server: 403 (ACCESS-REFUSED) with message "ACCESS_REFUSED - Login was refused using authen
tication mechanism PLAIN. For details see the broker logfile."
I tried authMechanism individually ('PLAIN', 'AMQPLAIN', 'EXTERNAL') but i'm getting same error.
Unable to create connection with rabbitMQ
var raabitmqSettings = {
protocol: 'amqp',
hostname: '10.250.18.31',
port: 5672,
username: 'sam',
password: 'sam#123',
vhost: '/',
authMechanism: ['PLAIN', 'AMQPLAIN', 'EXTERNAL']
}
amqp.connect(raabitmqSettings, function(err, conn) {
conn.createChannel(function(err, ch) {
console.log("\n\n" + ch);
}
}
Where can i see log file in rabbit mq or how enable logs in rabbitMQ?
Is it right way to create connection? Is there any setting in rabbitMQ server?
Use following code at receiver end
const open = await amqp.connect(setting);
var ch = await open.createChannel();
await ch.assertExchange("cronService", "direct");
var q = 'CronQueue';
ch.assertQueue(q, { durable: true });
ch.consume(q, async function(msg) {
console.log(" [x] Received %s", msg.content.toString());
}, { noAck: true });
return something;

EasyNetQ Consume Binary Message

I use the following code to publish a raw message to the queue:
using (var bus = RabbitHutch.CreateBus("host=myserver;virtualHost=myhost;username=xxx;password=yyy").Advanced)
{
var queue = bus.QueueDeclare("MyQueue");
var exchange = bus.ExchangeDeclare("MyExchange", ExchangeType.Topic);
var binding = bus.Bind(exchange, queue, "");
var properties = new MessageProperties();
var body = System.Text.Encoding.UTF8.GetBytes("This is the body of the message");
bus.Publish(exchange, "", false, false, properties, body);
}
The message got delivered to the queue and I see one message in the queue from RabbitMQ's console. However, when I try to consume it with the following code I'm not getting anything back:
bus.Consume(queue, (body, properties, info) => Task.Factory.StartNew(() =>
{
var message = Encoding.UTF8.GetString(body);
Console.Out.WriteLine("Got message: '{0}'", message);
}));
I can see the message is delivered from Rabbit's console but nothing gets printed out and the message is still in the queue. What am I missing?