MassTransit message encryption and routing slip events - masstransit

I have enabled encryption for my RabbitMQ bus as per MassTransit documentation:
bus = Bus.Factory.CreateUsingRabbitMq(rabbit =>
{
rabbit.Durable = true;
rabbit.Host(new Uri(settings.ServerUri), h =>
{
h.Username(settings.Username);
h.Password(settings.Password);
});
rabbit.ClearMessageDeserializers();
rabbit.UseEncryption(Convert.FromBase64String("..."));
...
});
I have also added subscription for a routing slip completed event:
var builder = new RoutingSlipBuilder(NewId.NextGuid());
builder.AddActivity(...);
await builder.AddSubscription(queueUri, RoutingSlipEvents.Completed,
x => x.Send<xxxRoutingSlipCompleted>(new { ctx.Data.CorrelationId }));
While all other messages get encrypted as expected, routing slip events get sent in plain text (as can be seen in RabbitMQ queue) and result in the following exception:
System.Runtime.Serialization.SerializationException:
No deserializer was registered for the message content type: application/vnd.masstransit+json.
Supported content types include application/vnd.masstransit.v2+aes
at MassTransit.Serialization.SupportedMessageDeserializers.Deserialize(ReceiveContext receiveContext)
at MassTransit.Pipeline.Filters.DeserializeFilter.Send(ReceiveContext context, IPipe`1 next)
at GreenPipes.Filters.RescueFilter`2.GreenPipes.IFilter<TContext>.Send(TContext context, IPipe`1 next)
Is there some additional configuration that needs to be applied to routing slips (I can't see anything relevant on the ISendEndpoint interface) or is this a bug in MassTransit?

Related

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
}

Twilio awaits response, I don't want server to respond

I am using a Slack webhook to process incoming SMS messages from Twilio. However, the way I have it set up, It seems that Twilio is expecting the web server (slack) to respond to it. This causes errors to be generated in Twilio, and I obviously don't want errors because I'll be getting emails.
I am using the twilio-ruby gem in Ruby to send out the SMS messages, and using the slack-ruby-client to monitor incoming messages from Slack.
How do I stop Twilio from trying to expect a response from the web server when it POSTS to the Slack webhook? Is that even possible or do I have this all configured incorrectly?
EDIT
Here's the function that I have which sends the forwarded SMS to Slack:
const https = require("https");
// Make sure to declare SLACK_WEBHOOK_PATH in your Environment
// variables at
// https://www.twilio.com/console/runtime/functions/configure
exports.handler = (context, event, callback) => {
// Extract the bits of the message we want
const { To, From, Body } = event;
// Construct a payload for slack's incoming webhooks
const slackBody = JSON.stringify({
text: `!asi SMS\nFrom: ${From}\nMessage: ${Body}`
});
// Form our request specification
const options = {
host: "hooks.slack.com",
port: 443,
path: context.SLACK_WEBHOOK_PATH,
method: "POST",
headers: {
"Content-Type": "application/json",
"Content-Length": slackBody.length
}
};
// send the request
const post = https.request(options, res => {
// only respond once we're done, or Twilio's functions
// may kill our execution before we finish.
res.on("end", () => {
// respond with an empty message
callback(null, new Twilio.twiml.MessagingResponse());
});
});
post.write(slackBody);
post.end();
};
Twilio developer evangelist here.
Twilio is always going to expect at least a 200 response or will timeout at 15 seconds for incoming message webhooks.
You could avoid the error messages by using something in between Twilio and Slack, like Zapier (example in this blog post) or using a Twilio Function (as described here) or with Twilio Studio (from the documentation here).
Hope one of those ideas helps!
Update
Further to my earlier answer, and given the code you used to make the call, I have an update.
When making a request using Node's built in https module you will not get the end event until you have read the data. This is what is causing the timeout between Twilio and the Twilio Function, you are never responding to it because you don't consume the data from the request.
In a quick test I found that just listening for the data event meant that the end event did fire. So update your function to:
const post = https.request(options, res => {
// only respond once we're done, or Twilio's functions
// may kill our execution before we finish.
res.on("data", () => {});
res.on("end", () => {
// respond with an empty message
callback(null, new Twilio.twiml.MessagingResponse());
});
});
And it should work.

User specific publish (subscriptions)

Here's a small issue I faced and couldn't find much info in the documentation. I am trying to create private chat messages. We have the following code to subscribe a user to a topic:
export const resolvers = {
Subscription: {
somethingChanged: {
subscribe: () => pubsub.asyncIterator('chat_messages'),
},
},
}
and to publish
pubsub.publish('chat_messages', { somethingChanged: { sender_id: 1, receiver_id: 2, message: 'test' }});
I have used onConnect to verify that the user is authenticated
const server = new ApolloServer({
typeDefs,
resolvers,
subscriptions: {
onConnect: (connectionParams, webSocket) => {
...
if (!authenticated) throw error
...
},
},
...
})
This works well when I want to subscribe users to a particular topic for example. But how do I implement, private user to user communication? I have tried the withFilter but can't seem to implement user specific authorization(with respect to a message) checks.
Here is a demo: https://github.com/mrdulin/apollo-server-express-starter/tree/master/src/subscription/demo-1
With these features:
jwt based auth for websocket connection
User channel which means who can receive message, who can not.
There are some conceptions you need know:
there are two types user: requestUser and subscribeUsers(include requestUser)
you should write the code in filterFn, for who can receive the message which requestUser send.
For example:
There are three subscribe users: s1(client-1), s2(client-2), s3(client-3)
When a request user(client-4) send a message(maybe mutation), you can get subscribe users and request users through context argument of filterFn.
According to these two type users' informations. You can write your own bussiness logic in filterFn to decide who can receive message, who can't.
P.S. beside context, you can get variables argument in filterFn from client. That will give more information to decide who can receive message and who can't
Sorry for my English!

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);

Dynamic queues not created when subscribing to topic Spring WebSocket with STOMP?

I am developing push notification to all subset of users who subscribed to particular event.
User subscribes to topic in RabbitMQ with format: user-id.event-type.id.
I use Spring Websocket, Stomp, RabbitMQ and on frontend SockJS and Angular JS.
User should be notified of all actions (comments etc, date change) about event.
What we have so far:
First I authenticate through REST webservice endpoint, and put my token to Cookie. Then we connect to
websocket. Users subscribes to topic (/topic/user-45.meeting.1235) and they get notification. But my problem is some users do not receive notification. For second user, for some reason queue is not created in RabbitMQ. Anyone knows why?
This is my broker settings in Spring applicationContext.xml:
<websocket:message-broker application-destination-prefix="/app">
<websocket:stomp-endpoint path="/stomp">
<websocket:sockjs/>
</websocket:stomp-endpoint>
<websocket:stomp-broker-relay relay-host="localhost" relay-port="61613" system-login="guest" system-passcode="guest" prefix="/queue, /topic"/>
</websocket:message-broker>
and this is how subscribe through Sockjs:
var ws = new SockJS('http://' + location.host + path);
var stompClient = Stomp.over(ws);
stompClient.connect({
username: '',
password: '',
host: '/'
}, function () {
stompClient.subscribe('/topic/user-45.meeting.' + obj.id,
function (message) {
console.log(message);
}, {
persistent: true
});
});
UPDATED
If we specify unique Id field in SUBSCRIBE frame, it creates unique queue for each user. Is this way to go?
As per my knowledge you need to subscribe the \queue not \topic.By doing this you don't need to customize topic name for different users,that will be handled by sockjs depending on logged user.And at server side you can also send messages to particular user by using \queue\user\{username}\{name of queue}

Resources