MassTransit sends a durable message when a non durable one is configured - masstransit

I'm trying to send a message to an queue. The queue exists already and is configured as non durable. Here's my code:
ServiceBus = Bus.Factory.CreateUsingRabbitMq(sbc =>
{
sbc.PurgeOnStartup = true;
sbc.Durable = false;
sbc.Exclusive = false;
sbc.Host(new Uri($"rabbitmq://{RabbitMqHost}"), cfg =>
{
cfg.ConfigureRabbitMq();
});
});
ServiceBus.Request(
new Uri(serviceUri),
new EngineStartingMessage() { Version = ApplicationConfig.SystemVersion },
rCfg =>
{
rCfg.Durable = false;
rCfg.Timeout = new TimeSpan(0, 0, 30);
rCfg.Handle<EngineStartingResponse>(async hContext =>
{
//Response handling
});
});
As you can see Durable is set to false. On ServiceBus.Request I get the following exception:
The AMQP operation was interrupted: AMQP close-reason, initiated by
Peer, code=406, text="PRECONDITION_FAILED - inequivalent arg 'durable'
for exchange 'QUEUENAMEHERE' in vhost '/': received 'true' but current
is 'false'", classId=40, methodId=10, cause=
Any ideas why the message is still sent as durable?

That Durable flag only specifies that the particular request message should not be persisted to disk.
If you want to fix this, add ?durable=false to the serviceUri, to match what's being specified at the receive endpoint which handles the request.

Related

How I can send additional header when configuring RabbitMQ queue?

I want to use Single Active Consumer feature of RabbitMQ as described here: https://www.rabbitmq.com/consumers.html#single-active-consumer.
Single active consumer can be enabled when declaring a queue, with the x-single-active-consumer argument set to true, e.g. with the Java client:
Channel ch = ...;
Map<String, Object> arguments = new HashMap<String, Object>();
arguments.put("x-single-active-consumer", true);
ch.queueDeclare("my-queue", false, false, false, arguments);
I couldn't find a way to add custom header at the moment of queue declaration.
I am configuring my endpoints like this:
busConfigurator.UsingRabbitMq((context, rabbitConfig) =>
{
// ...
rabbitConfig.ReceiveEndpoint(endpointName, (IReceiveEndpointConfigurator a) =>
{
a.ConfigureConsumer(context, consumerType);
// a.ConfigureSend(...)
// a.ConfigureReceive(...)
});
});
With ConfigureSend and ConfigureReceive I can add/read headers to the message, but I need to add x-single-active-consumer when queue is created in rabbit.
I found the issue, I was casting endpoint configurator to IReceiveEndpointConfigurator, while it should be IRabbitMqReceiveEndpointConfigurator (which is default type)
Correct code:
busConfigurator.UsingRabbitMq((context, rabbitConfig) =>
{
// ...
rabbitConfig.ReceiveEndpoint(endpointName, (a) =>
{
a.SingleActiveConsumer = true;
a.ConfigureConsumer(context, consumerType);
});
});

AWS Websocket doesnt receive previous message until new message is sent

Most of the time the messages are passed normally, but a couple messages in particular arent recieved until the recieving client sends a message. This happens everytime for specific methods/messages, but not at all for others.
Example: user1 sends a message, user2 then sends a message to receive message from user1.
Related Material
Deleted question: websocket receives previous message only when new message is sent
Github issue: webSocket client does not receive messages before sending...
We ran into this issue and the solution had to do with how we wrote our promises. We initially used the sample code provided by Amazon
https://github.com/aws-samples/simple-websockets-chat-app/blob/master/sendmessage/app.js#L26
const postCalls = connectionData.Items.map(async ({ connectionId }) => {
try {
await apigwManagementApi.postToConnection({ ConnectionId: connectionId, Data: postData }).promise();
} catch (e) {
if (e.statusCode === 410) {
console.log(`Found stale connection, deleting ${connectionId}`);
await ddb.delete({ TableName: TABLE_NAME, Key: { connectionId } }).promise();
} else {
throw e;
}
}
});
And I'm pretty sure having an async function as a map function doesn't work properly or reliably (for whatever reason. maybe this is documented somewhere), so we changed it to a simple for loop and it fixed the issue.
for(const connection of connectionData.Items) {
const connectionId = connection.connectionId;
...same logic goes here
}

MassTransit MessageRequestClient timeout issue

We have two services which exchange messages via MassTransit on top of RabbitMQ.
The goal is to send a message in a request/response way. Here's the code of the service which listens for a message, let's call it Service1:
Bus.Factory.CreateUsingRabbitMq(
sbc =>
{
var host = sbc.Host(new Uri($"rabbitmq://{RabbitMqHost}"), h =>
{
h.ConfigureRabbitMq();//Custom extension to specify credentials
});
sbc.ReceiveEndpoint(host, "CUSTOM_QUEUE_NAME", ep =>
{
ep.Exclusive = false;
ep.AutoDelete = true;
ep.Durable = false;
ep.PrefetchCount = 1;
ep.Handler<EngineStartingMessage>(async context =>
{
//SourceAddress and ResponseAddress are auto generated queues
//Message processing is done here
context.Respond(response);
});
});
});
The code of the service which sends a message and process the result, let's call it Service2:
var requestClient =
new MessageRequestClient<EngineStartingMessage, EngineStartingResponse>(
EntityServiceBus,
new Uri("CUSTOM_QUEUE_NAME?durable=false&autodelete=true&exclusive=false"),
new TimeSpan(0, 0, 30));
var engineStartResponse = requestClient.Request(new EngineStartingMessage() { Version = SystemVersion }).Result;
When I run the above code I can see Service1 gets a request and calls context.Respond(response); but on the Service2 side I always get a Timeout exception. Since, a message can make it from Service2 to Service1 I assume there are no network related issues. The timeout is pretty high as well. The message processing on Service1 end takes less than a second. So I think a response message is just not routed properly and I don't understand why. What is suspicious to me is that SourceAddress and ResponseAddress contain auto generated values and not "CUSTOM_QUEUE_NAME?durable=false&autodelete=true&exclusive=false". Any ideas what I'm doing wrong?
You should start Bus, on your service start, like it shown here
await busControl.StartAsync(source.Token);

How to send and receive data from webstomp websocket provided by rabbitmq?

I am writing a chat application without explicit server side web socket.
I am using RabbitMQ webstomp as the web socket container and plain Javascript as the cleint to both send and receive data.
Below is the flow :
Browser -> native websocket/sockjs -> rabbitmq /sockjs websocket (ws://127.0.0.1:15674/ws or http://localhost:15674/stomp) -> put messages to queue.
However while testing the application, I am not able to send the data directly to ws://127.0.0.1:15674/ws. I am just able to connect to it.
I use the below template to send and receive data on client Javascript.
ws = new WebSocket('ws://127.0.0.1:15674/ws');
client = Stomp.over(ws);
client.connect('guest','guest',on_connection,on_connect_error,'/');
client.send(queue, {'reply-to':'/temp-queue/logs',priority: 9}, "msg" );
client.onreceive = func()
The problem,most likely,in your code is:
client.send(queue, {'reply-to':'/temp-queue/logs',priority: 9}, "msg" );
you have to send the message to a topic
I suggest to see the example here: https://github.com/rabbitmq/rabbitmq-web-stomp-examples
Here is a rapid example i made starting for the original example:
var client = Stomp.client('ws://localhost:15674/ws');
client.debug = pipe('#second');
var print_first = pipe('#first', function(data) {
client.send('/topic/test', {"content-type":"text/plain"}, data);
});
var on_connect = function(x) {
id = client.subscribe("/topic/test", function(d) {
print_first(d.body);
});
};
var on_error = function() {
console.log('error');
};
client.connect('guest', 'guest', on_connect, on_error, '/');

myWebSocketSubject.multiplex(..).subscribe().unsubscribe() closes connection, event further observers exists

The following code will close the connection, event further observers exists on the myWebSocketSubject:
myWebSocketSubject.Observable.webSocket('ws://mysocket');
myWebSocketSubject.subscribe();
myWebSocketSubject.multiplex(..).subscribe().unsubscribe()
// the connection closed now
My expectation was, that the connection gets closed with the last unsubscribe() call (and not with the first one).
Use Case
If I get it right, with the multiplex(..) operator, on create and complete a message is send to the socket, which e.g. allows to un-/subscribe on server side to specific event.
My preferred Web Socket service could therefore look like as below. There exists only one connection, and this single connection provides several streams. On first subscription to the web socket the connection gets created; and with the last unsubscribe call the connection gets closed. For each data-stream a un-/subscribe message is sent once.
I haven't found a solution to use the WebSocketSubject.multiplex(..) method...
Preferred Example Web Socket Service
export class WebSocketService {
connection: WebSocketSubject<any>;
constructor() {
this.connection = Observable.webSocket<any>(_createConfig())
}
dataStream(eventType: string): Observable<WebSocketMessage> {
return connection.multiplex(
() => new WebSocketMessage("WebSocket.Subscribe." + eventType),
() => new WebSocketMessage("WebSocket.Unsubscribe." + eventType),
message => (message.type == eventType)
)
.retry() // reconnect on error and send subscription messages again
.share(); // send messages on last/fist un-/subscribe on this stream
}
// ...
}
export class WebSocketMessage {
type: string;
data: any;
constructor(command: string, data?:any) {
this.type = command;
this.data = data || undefined;
}
}
I have written the following test case which fails...
it('should able to handle multiple subscriptions', () => {
const subject = Observable.webSocket(<any>{url: 'ws://mysocket'});
const sub1 = subject.subscribe();
const sub2 = subject.subscribe();
const socket = MockWebSocket.lastSocket;
socket.open();
sinon.spy(socket, 'close');
sub1.unsubscribe();
// Fails, because the socket gets closed on first unsubscribe
expect(socket.close).have.not.been.called;
sub2.unsubscribe();
expect(socket.close).have.been.called;
});
If I get it right the share operator would do the trick. But after using the operator, the multiplex method is not available.
Thanks for any feedback, input, ...!

Resources