We are writing a test chat application using the Azure service bus backplane. We have stripped it down to barebones but there are pockets of "lag" where messages sent don't get received for up to 15 seconds later.
Startup.cs
string connectionString = GetServiceBusConnectionString();
GlobalHost.DependencyResolver.UseServiceBus(connectionString, "Chat");
app.MapSignalR();
Chathub.cs
protected void MsgAll(User user, string content)
{
Clients.All.broadcastMessage(new Message() { Content = content, NickName = user.NickName, Status = user.Status, TimeStamp = DateTime.Now });
}
Chat.js
self.chat.client.broadcastMessage = function (res) {
self.messages.push(new messageItem(res));
var objDiv = document.getElementById("chat-messages");
objDiv.scrollTop = objDiv.scrollHeight;
};
It works fine when its standalone, but starts lagging intermittently when we add the backplane, even on one server. Any tips/help appreciated.
Additional info:
using defaults
Looking at mgmt portal we see 5 topics created
Related
I'm creating a ping function using azure functions that needs to check if a service bus in another region is operating so it can update the status of the whole system (two regions). What is the best way to check the status of the other service bus \ topics in the other service bus?
I found this code which I could adapt to GetTopic() instead of the Queue:
string connectionString = "connection string";
var namespaceManager = NamespaceManager.CreateFromConnectionString(connectionString);
var queueDescription = namespaceManager.GetQueue("queue name");
var status = queueDescription.Status;
However, it has been recommended that this library (WindowsAzure.ServiceBus) has been updated to Azure.Messaging.ServiceBus and I can't find a similar way to do this in the newer library.
Please point me in the right direction?
ServiceBusAdministrationClient from Package 'Azure.Messaging.ServiceBus v7.8.1' can be used.
ServiceBusAdministrationClient.GetQueueAsync returns the QueueProperties incl. Status:
https://learn.microsoft.com/en-us/dotnet/api/azure.messaging.servicebus.administration.queueproperties.status?view=azure-dotnet#azure-messaging-servicebus-administration-queueproperties-status
public Azure.Messaging.ServiceBus.Administration.EntityStatus Status { get; set; }
The current status of the queue (Enabled / Disabled).
ServiceBusAdministrationClient serviceBusAdministrationClient = new ServiceBusAdministrationClient();
var status = await serviceBusAdministrationClient.GetQueueAsync("myQueue").Status;
My goal is to:
In scheduled functions - add message to SignalR
In SPA application (vue.js) subscribe to the event and call API to update the view
For now I'm trying to get anything to/from SignalR in my Function app (isolated, .net 6.0).
What I have in a function app:
[Function("negotiate")]
public HttpResponseData Negotiate(
[HttpTrigger(AuthorizationLevel.Anonymous, "post")] HttpRequestData req,
[SignalRConnectionInfoInput(HubName = "AdminHub", ConnectionStringSetting = "AzureSignalRConnectionString")] SignalRConnectionInfo connectionInfo)
{
_logger.LogInformation($"SignalR Connection URL = '{connectionInfo.Url}'");
var response = req.CreateResponse(HttpStatusCode.OK);
response.Headers.Add("Content-Type", "text/plain; charset=utf-8");
response.WriteString($"Connection URL = '{connectionInfo.Url}'");
return response;
}
}
[Function("SendMessage")]
[SignalROutput(HubName = "AdminHub", ConnectionStringSetting = "AzureSignalRConnectionString")]
public SignalRMessage SendMessage(
[HttpTrigger(AuthorizationLevel.Anonymous, "get")] Microsoft.Azure.Functions.Worker.Http.HttpRequestData req)
{
return
new SignalRMessage
{
Target = "cancelToHandle",
MethodName = "cancelToHandle",
Arguments = new[] { "hello" }
};
}
[Function("SignalRTest")]
public static async Task SignalRTest([SignalRTrigger("AdminHub", "messages", "cancelToHandle", ConnectionStringSetting = "AzureSignalRConnectionString")] string message, ILogger logger)
{
logger.LogInformation($"Receive {message}.");
}
Negotiate function is not called. When should it be called?
If I call SendMessage, no error, but nothing happens in SignalR service. Should I see connections and messages there? (zero in the Metrics for now).
I've tried to create a test "emulator" client - just a console application:
var url = "http://<azureSignalRUrl>/AdminHub";
var connection = new HubConnectionBuilder()
.WithUrl(url)
.WithAutomaticReconnect()
.Build();
// receive a message from the hub
connection.On<string, string>("cancelToHandle", (user, message) => OnReceiveMessage(user, message));
await connection.StartAsync();
// send a message to the hub
await connection.InvokeAsync("SendMessage", "ConsoleApp", "Message from the console app");
void OnReceiveMessage(string user, string message)
{
Console.WriteLine($"{user}: {message}");
}
and it throws the exception ": 'A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond. (:80)'
I think I'm missing overall understanding of what is supposed to happen:
when should negotiate function be triggered
can I see messages that I send in Azure portal (in SignalR service)?
how can I easily receive them in testing purposes
what do parameters/properties mean (target / method name / category). Example:
SignalRTriggerAttribute has the following constructor
public SignalRTriggerAttribute(string hubName, string category, string #event, params string[] parameterNames);
and Output binding receives any custom model I create?
which settings should be set in SignalR service - for now all I set it Serverless mode + CORS
Here are the few link which will help in using SignalIr service extension in functions
Using SignalIr service extension
https://github.com/Azure/azure-functions-dotnet-worker/blob/main/samples/Extensions/SignalR/SignalRFunction.cs
Below is the sample link for triggering negotiate function
https://github.com/Log234/azure-functions-signalr-dotnet-isolated-demo/blob/main/SignalRDemo/NegotiationFunctions.cs
for complete understanding of SignalIR here is the Github and MS document.
I'm new to azure service bus and masstransit. I'm looking for a solution to a specific situation.
I have a azure service bus topic with multiple subscribers. Subscriber will receive message based on filters. I've created the topic and subscriber with code below
class Program
{
static void Main(string[] args)
{
string connectionString = "Endpoint connection string";
// the names of topics and subscriptions we'll be working with
const string topicName = "MyTestTopic";
const string allMessagesSubName = "AllMessages";
const string filteredSubName1 = "Filtered1";
const string filteredSubName2 = "Filtered2";
// let's create the topic if it doesn't already exist...
var namespaceManager = NamespaceManager.CreateFromConnectionString(connectionString);
if (!namespaceManager.TopicExists(topicName))
{
var td = new TopicDescription(topicName);
namespaceManager.CreateTopic(td.Path);
}
if (!namespaceManager.SubscriptionExists(topicName, allMessagesSubName))
{
namespaceManager.CreateSubscription(topicName, allMessagesSubName);
}
if (!namespaceManager.SubscriptionExists(topicName, filteredSubName1))
{
namespaceManager.CreateSubscription(
new SubscriptionDescription(topicName, filteredSubName1),
new Microsoft.ServiceBus.Messaging.SqlFilter("From LIKE '%Smith'"));
}
if (!namespaceManager.SubscriptionExists(topicName, filteredSubName2))
{
namespaceManager.CreateSubscription(
new SubscriptionDescription(topicName, filteredSubName2),
new Microsoft.ServiceBus.Messaging.SqlFilter("sys.Label='important'"));
}
var message1 = new BrokeredMessage("Hello World");
var message2 = new BrokeredMessage("Second message");
message2.Label = "important";
var message3 = new BrokeredMessage("Third message");
message3.Properties["From"] = "Kelly Smith";
message3.Label = "information";
var client = TopicClient.CreateFromConnectionString(connectionString, topicName);
client.Send(message1);
client.Send(message2);
client.Send(message3);
client.Close();
}
}
Here in the code we're adding Message custom properties like From.
Now I want to send such message using masstransit. In masstransit I cannot find any option of adding Message custom properties using the Publish() method. Is there any way that I can send these messages using masstransit where these filters can be used?
NB: I've read the answer of this question But the anwer here tells us to filter the messages in subscriber side. What I want is that this filtering will occur before reaching the subscriber.
When using Azure Service Bus with MassTransit, you can add subscription endpoints in additional to regular endpoints. When configuring a subscription endpoint, you should be able to specify rules and/or filters as part of the subscription. Which is exactly what you're doing above, so that is handled.
The other part, adding properties to the message, can be done by adding text headers to the SendContext. Those headers are copied to the message Properties collection, which I believe can be used to filter messages using a "SQL" filter (which is configured on the subscription endpoint, or the topic subscription on a receive endpoint).
I have an asp.net MVC 5 application. Now I want to have a new feature allow me to receive GPS signal from devices and update devices real time in web client side.
My plan is to use RabbitMQ to handle message queue and SignalR to notify clients for postion update
My code in Rabbit consumer console application like this
var client = GlobalHost.ConnectionManager.GetHubContext<MyHub>().Clients;
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
var queueName = channel.QueueDeclare().QueueName;
channel.ExchangeDeclare("mychannel", "fanout");
channel.QueueBind(queueName, "mychannel", "");
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var body = ea.Body;
var message = Encoding.UTF8.GetString(body);
Console.WriteLine("[x] Receive {0}", message);
client.All.hello(message);
};
channel.BasicConsume(queue: queueName,
autoAck: true,
consumer: consumer);
Console.WriteLine("Press Enter to quit");
Console.ReadLine();
}
}
But the code is not fired when I produce a message to RabbitMQ. If I remove code of signalR client:
var client = GlobalHost.ConnectionManager.GetHubContext<MyHub>().Clients;
things work as expected and I can receive message as usual
My question is:
Is my approach correct
if the approach correct then how to make it work?
Many thanks
I am trying to build a simple Web API REST service in Azure with a service bus queue worker on the back end. I can send a single message from the Web API to the worker just fine. However, I was trying to send more messages just to see how everything works. So, I created a simple controller that looks like this:
for (int i = 0; i < 100; i++)
{
var msg = new BrokeredMessage("Ping");
BioConnector.QueueConnector.OrdersQueueClient.Send(msg);
}
When I call the controller, I am only getting about 1/2 or so of the messages being received by the worker. The rest seem to be dropped.
I had issues with getting only about half the messages using the sample code posted here, so I wrote my own test code. I've tried it with > 100 queue messages and have always had 100% send/rec'd parity. Perhaps you had a similar issue with the code.
Create a new C# console project.
Add a reference to the Microsoft.ServiceBus assembly located in C:\Program Files\Microsoft SDKs\Windows Azure.NET SDK\2012-06\ref\Microsoft.ServiceBus.dll.
In the app.config, change it to this with your own values provided:
<appSettings>
<add key="Microsoft.ServiceBus.ConnectionString" value="Endpoint=sb://blahblah.servicebus.windows.net/;SharedSecretIssuer=owner;SharedSecretValue=pDk0b....=" />
</appSettings>
Add these using directives:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using Microsoft.ServiceBus;
using Microsoft.ServiceBus.Messaging;
using System.Configuration;
using System.Threading;
Change the code method to the following:
class Program
{
static void Main(string[] args)
{
string connectionString = ConfigurationSettings.AppSettings["Microsoft.ServiceBus.ConnectionString"];
var namespaceManager = NamespaceManager.CreateFromConnectionString(connectionString);
QueueDescription queueDesc = new QueueDescription("TestQueue");
if (!namespaceManager.QueueExists(queueDesc.Path))
{
namespaceManager.CreateQueue(queueDesc);
}
QueueClient topicClient = QueueClient.CreateFromConnectionString(connectionString, queueDesc.Path);
int sentMsgCount = 0;
int recdMsgCount = 0;
for (int i = 0; i < 100; i++)
{
BrokeredMessage msg = new BrokeredMessage("Test message " + i);
topicClient.Send(msg);
sentMsgCount++;
Console.WriteLine("Sent Message: " + msg);
}
QueueClient subClient = QueueClient.CreateFromConnectionString(connectionString, queueDesc.Path);
bool moreMessages = true;
while (moreMessages)
{
BrokeredMessage recdMsg = subClient.Receive(TimeSpan.FromSeconds(3));
if (recdMsg != null)
{
Console.WriteLine("Received Message: " + recdMsg);
recdMsgCount++;
recdMsg.Complete();
}
else
{
moreMessages = false;
}
}
Console.WriteLine("# of sent msgs: " + sentMsgCount + ", # of rec'd msgs: " + recdMsgCount);
Console.Read();
}
}
This was a weird problem. Through a random walk through "trying things" I ended up changing the string name of the queue and then everything started working again. I didn't change anything but the name of the queue - no changes to any configuration parameters at all.
It appears to be something buggy with that particular queue on Azure.
Azure Service Bus provides durable messaging so you will not loose any messages. Some items to investigate further:
1) Is there another instance of the worker role that is pulling off messages from that queue
2) are you using peek-lock as the receive mode as that will be the only way to guarantee at least once delivery. Receive and delete mode does not have the guarantee
3) are the messages going into dead-lettered queue due to either message expiry or exceeding max delivery count, I.e. They are received but not completed several times
4) if none of the above apply then raise a support ticket and the Azure product team can investigate the symptoms because as I mentioned this is a durable messaging system so no messages will be "lost".
I had the WindowsAzure.ServiceBus NuGet package in my project and used QueueClient.Send() to send messages and faced the same messages lost issue.
My solution to completely solve the issue:
On the send side, I had to use REST API to send messages.
On the receive side, this is how I extracted the message body:
using (var stream = brokeredMessage.GetBody<Stream>())
{
using (var streamReader = new StreamReader(stream, Encoding.UTF8))
{
var msg = streamReader.ReadToEnd();
// Convert the JSON message to an object
// var obj = JsonConvert.DeserializeObject<ObjectType>(msg);
}
}