When I try the below code to connect to the mosquitto broker, as you know, connecting to the broker might takes few seconds/minutes, and during that time when the button pressed to connect, it remains pressed till the connection established and when the connection established the button released back to its normal state. As far as I know, there are two way for connecting a client using paho java API, the blocking method and unblocking method. my question is, how to use the unblocking method? beow is my attempt to use the blocking method
Code_1:
//mqttFactory
public final class MQTTClientFactory {
public static MqttClient newClient(String ip, int port, String clientID) throws MqttException {
String serverURI = formURI(ip, port);
MqttClient client = new MqttClient(serverURI, clientID).;
return client;
}
MqttConnectOptions opts = getClientOptions();
client = MQTTClientFactory.newClient(broker, port, clientID);
if (client != null) {
System.out.println("Client is not Null");
client.setCallback(AsynchCallBack);
if (opts != null) {
client.connectWithResult(opts).setActionCallback(synchCallBack);
if (client.isConnected()) {
System.out.println("Client CONNECTED.");
}
}
}
what button? establishing a connection is almost instantly.
There are asynchronous versions of mqtt. Code samples for that. If you want to make the synchronous non-blocking. You could start it up in another thread.
Related
I am trying to learn to Build Microservices based app where Microservices would be communicating via some service bus. In my case, I am using Azure Service bus.
With referring to below link an initial system is set up. Messages are reaching to the queue.
https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-dotnet-multi-tier-app-using-service-bus-queues
But as next step or mimicking real app, I have OrderAPI to handle the orders.
This is how my WorkerRole class looks like
namespace OrderProcessingRole
{
public class WorkerRole : RoleEntryPoint
{
// The name of your queue
const string QueueName = "ProcessingQueue";
// QueueClient is thread-safe. Recommended that you cache
// rather than recreating it on every request
QueueClient Client;
ManualResetEvent CompletedEvent = new ManualResetEvent(false);
public override void Run()
{
Trace.WriteLine("Starting processing of messages");
// Initiates the message pump and callback is invoked for each message that is received, calling close on the client will stop the pump.
Client.OnMessage((receivedMessage) =>
{
try
{
// Process the message
Trace.WriteLine("Processing Service Bus message: " + receivedMessage.SequenceNumber.ToString());
}
catch
{
// Handle any message processing specific exceptions here
}
});
CompletedEvent.WaitOne();
}
public override bool OnStart()
{
// Set the maximum number of concurrent connections
ServicePointManager.DefaultConnectionLimit = 12;
// Create the queue if it does not exist already
string connectionString = CloudConfigurationManager.GetSetting("Microsoft.ServiceBus.ConnectionString");
var namespaceManager = NamespaceManager.CreateFromConnectionString(connectionString);
if (!namespaceManager.QueueExists(QueueName))
{
namespaceManager.CreateQueue(QueueName);
}
// Initialize the connection to Service Bus Queue
Client = QueueClient.CreateFromConnectionString(connectionString, QueueName);
return base.OnStart();
}
public override void OnStop()
{
// Close the connection to Service Bus Queue
Client.Close();
CompletedEvent.Set();
base.OnStop();
}}}
I am not sure, how & where should I call the OrdersAPI when service bus is in place.
I am guessing it would be in
OnStart() ->
Client.OnMessage((receivedMessage) =>
{
try
{
//Order API call here
}
catch
{
}
});
If my guess is right, then how I call my OrderAPI which is hosted on
http://localhost:8090/api/order
Thanks.
Assuming OrdersAPI is your Web API endpoint receiving requests from a browser, it would construct Azure Service Bus messages and send to a queue. Your Worker Role then would receive those messages and process. Processing would not be performed in Web API.
The Orders API should be called inside
Run() ->
Client.OnMessage((receivedMessage) =>
{
try
{
//Order API call here
}
catch
{
}
});
Use HttpClient for triggering the API. By doing this, the API will be called whenever a message is received from the Queue.
As the worker role is hosted in Azure environment, the APIs hosted somewhere public can only be called from here. It does not identify the API hosted in local machine. Try hosting the API in Azure App Service or Azure Function App.
I need to achieve the impact of waitForConfirmsOrDie in core java implementation in spring . In core java it is achievable request wise ( channel.confirmSelect , set Mandatory , publish and Channel.waitForConfirmsOrDie(10000) will wait for 10 sec)
I implemented template.setConfirmCallback ( hope it is same as PublisherCallbackChannel.Listener) and it works great , but ack/nack is at a common place ( confirm call back ) , for the individual sender no idea like waitForConfirmsOrDie , where he is sure within this time ack hasn't came and can take action
do send methods wait for specified period internally like waitForConfirmsOrDie in spring if ack hasn't came and if publisherConfirms is enabled.
There is currently no equivalent of waitForConfirmsOrDie in the Spring API.
Using a connection factory with publisher confirms enabled calls confirmSelect() on its channels; together with a template confirm callback, you can achieve the same functionality by keeping a count of sends yourself and adding a method to your callback to wait - something like...
#Autowired
private RabbitTemplate template;
private void runDemo() throws Exception {
MyCallback confirmCallback = new MyCallback();
this.template.setConfirmCallback(confirmCallback);
this.template.setMandatory(true);
for (int i = 0; i < 10; i++) {
template.convertAndSend(queue().getName(), "foo");
}
confirmCallback.waitForConfirmsOrDie(10, 10_000);
System.out.println("All ack'd");
}
private static class MyCallback implements ConfirmCallback {
private final BlockingQueue<Boolean> queue = new LinkedBlockingQueue<>();
#Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
queue.add(ack);
}
public void waitForConfirmsOrDie(int count, long timeout) throws Exception {
int remaining = count;
while (remaining-- > 0) {
Boolean ack = queue.poll(timeout, TimeUnit.MILLISECONDS);
if (ack == null) {
throw new TimeoutException("timed out waiting for acks");
}
else if (!ack) {
System.err.println("Received a nack");
}
}
}
}
One difference, though is the channel won't be force-closed.
Also, in a multi-threaded environment, you either need a dedicated template/callback per thread, or use CorrelationData to correlate the acks to the sends (e.g. put the thread id into the correlation data and use it in the callback).
I have opened AMQP-717 for us to consider providing something like this out of the box.
I am working on an application that needs to recognize when someone log's off from system.
I've set ping interval to 5 seconds. I also have public override Task OnConnected() and public override Task OnDisconnected(), and they are triggered each time client connects and disconnects (I remember clients names and connections while connecting, and remove those data from list when disconnected)
So, when a client log's off the system, his connection is lost and he doesn't send any ping response. I have this solution working, but when it takes too much time, around 30 seconds to run OnDisconnected function.
Is there any possibility to make this process faster? I have to detect this in at least 4-5 seconds.
EDIT: here is the code
Hub.cs:
public class SignalRConnection
{
public string ConnectionId { get; set; }
public string UserName { get; set; }
}
public static List<SignalRConnection> connections = new List<SignalRConnection>();
public override Task OnConnected()
{
connections.Add(new SignalRConnection() { ConnectionId = Context.ConnectionId, UserName=Context.User.Identity.Name});
return base.OnConnected();
}
public override Task OnDisconnected()
{
var forDelete = connections.FirstOrDefault(p => p.ConnectionId == Context.ConnectionId);
connections.Remove(forDelete);
Clients.All.logoffActions(forDelete.UserName);
return base.OnDisconnected();
}
Global.asax
GlobalHost.Configuration.ConnectionTimeout =TimeSpan.FromSeconds(6);
GlobalHost.Configuration.DisconnectTimeout = TimeSpan.FromSeconds(6);
GlobalHost.Configuration.KeepAlive = TimeSpan.FromSeconds(2);
You can detect what happens from javascript. This will help understanding what happens with the connection: http://www.asp.net/signalr/overview/guide-to-the-api/handling-connection-lifetime-events
Basically first, your connection goes in reconnecting state (can be slow connection, short interruption in connection ... ) In this state tries to connect again. By default 6 times every 5 seconds, which takes 30 seconds. If no success fires the disconnected event which is going to call your hub's OnDisconnected method.
You can use the reconnecting function in javascript, but in this state, client can still come back.
You can use something like this is JS:
var tryingToReconnect = false;
$.connection.hub.reconnecting(function() {
tryingToReconnect = true;
});
$.connection.hub.reconnected(function() {
tryingToReconnect = false;
});
$.connection.hub.disconnected(function() {
if(tryingToReconnect) {
notifyUserOfDisconnect(); // Your function to notify user.
}
});
When the connection is down $.connection.hub.reconnecting(function() { will be called instantly, (but the firing of this event doesn't always mean that the connection is down! It might just be a quick connection problem)
Another useful thing would be the connectionSlow event.
$.connection.hub.connectionSlow(function() {
notifyUserOfConnectionProblem(); // Your function to notify user.
});
Most importantly to understand the states and the transitions described in the linked description.
I hope it helps. Cheers!
I am trying to set up a lightweight HTML5 Server-Sent Event implementation on my MVC 4 Web, without using one of the libraries available to implement sockets and similars.
The lightweight approach I am trying is:
Client side:
EventSource (or jquery.eventsource for IE)
Server side:
long polling with AsynchController (sorry for dropping here the raw test code but just to give an idea)
public class HTML5testAsyncController : AsyncController
{
private static int curIdx = 0;
private static BlockingCollection<string> _data = new BlockingCollection<string>();
static HTML5testAsyncController()
{
addItems(10);
}
//adds some test messages
static void addItems(int howMany)
{
_data.Add("started");
for (int i = 0; i < howMany; i++)
{
_data.Add("HTML5 item" + (curIdx++).ToString());
} _data.Add("ended");
}
// here comes the async action, 'Simple'
public void SimpleAsync()
{
AsyncManager.OutstandingOperations.Increment();
Task.Factory.StartNew(() =>
{
var result = string.Empty; var sb = new StringBuilder();
string serializedObject = null;
//wait up to 40 secs that a message arrives
if (_data.TryTake(out result, TimeSpan.FromMilliseconds(40000)))
{
JavaScriptSerializer ser = new JavaScriptSerializer();
serializedObject = ser.Serialize(new { item = result, message = "MSG content" });
sb.AppendFormat("data: {0}\n\n", serializedObject);
}
AsyncManager.Parameters["serializedObject"] = serializedObject;
AsyncManager.OutstandingOperations.Decrement();
});
}
// callback which returns the results on the stream
public ActionResult SimpleCompleted(string serializedObject)
{ ServerSentEventResult sar = new ServerSentEventResult();
sar.Content = () => { return serializedObject; };
return sar;
}
//pushes the data on the stream in a format conforming HTML5 SSE
public class ServerSentEventResult : ActionResult
{
public ServerSentEventResult() { }
public delegate string GetContent();
public GetContent Content { get; set; }
public int Version { get; set; }
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
} if (this.Content != null)
{
HttpResponseBase response = context.HttpContext.Response;
// this is the content type required by chrome 6 for server sent events
response.ContentType = "text/event-stream";
response.BufferOutput = false; // this is important because chrome fails with a "failed to load resource" error if the server attempts to put the char set after the content type
response.Charset = null;
string[] newStrings = context.HttpContext.Request.Headers.GetValues("Last-Event-ID");
if (newStrings == null || newStrings[0] != this.Version.ToString())
{
string value = this.Content();
response.Write(string.Format("data:{0}\n\n", value));
//response.Write(string.Format("id:{0}\n", this.Version));
}
else
{
response.Write("");
}
}
}
}
}
The problem is on the server side as there is still a big gap between the expected result and what's actually going on.
Expected result:
EventSource opens a stream connection to the server,
the server keeps it open for a safe time (say, 2 minutes) so that I am protected from thread leaking from dead clients,
as new message events are received by the server (and enqueued to a thread safe collection such as BlockingCollection) they are pushed in the open stream to the client:
message 1 received at T+0ms, pushed to the client at T+x
message 2 received at T+200ms, pushed to the client at T+x+200ms
Actual behaviour:
EventSource opens a stream connection to the server,
the server keeps it open until a message event arrives (thanks to long polling)
once a message is received, MVC pushes the message and closes the connection.
EventSource has to reopen the connection and this happens after a couple of seconds.
message 1 received at T+0ms, pushed to the client at T+x
message 2 received at T+200ms, pushed to the client at T+x+3200ms
This is not OK as it defeats the purpose of using SSE as the clients start again reconnecting as in normal polling and message delivery gets delayed.
Now, the question:
is there a native way to keep the connection open after sending the first message and sending further messages on the same connection?
Instead of relying on SimpleComplete to send the data, you want to send the data using Response.Flush. By doing an AsyncManager.OutstandingOperations.Decrement(), you're telling the AsyncController that you're finished processing the request and you're ready to send the response and close the connection. Instead, you avoid calling OutStandingOperations.Decrement() until the connection is lost, etc. Whenever you want to push a message to the client, you directly call Response.Write and Response.Flush from some background thread. Also, AsyncControllers have a default timeout after which they automatically close the connection. To get around that, you'll want to use the NoAsyncTimeoutAttribute for the relevant actions.
As a side note, AsyncController's interface doesn't really allow a clean way of implementing a SSE stream; I would have personally implemented a HttpTaskAsyncHandler given that I was using Asp.NET MVC 4.
I'm struggling with the concept of creating a Jedis-client which listens infinitely as a subscriber to a Redis pubsub channel and handles messages when they come in.
My problem is that after a while of inactivity the server stops responding silently. I think this is due to a timeout occurring on the Jedis-client I subscribe with.
Would this likely indeed be the case? If so, is there a way to configure this particular Jedis-client to not timeout? (While other Jedispools aren't affected with some globally set timeout)
Alternatively, is there another (best practice) way of what I'm trying to achieve?
This is my code, (modified/ stripped for display) :
executed during web-server startup:
new Thread(AkkaStarter2.getSingleton()).start();
AkkaStarter2.java
private Jedis sub;
private AkkaListener akkaListener;
public static AkkaStarter2 getSingleton(){
if(singleton==null){
singleton = new AkkaStarter2();
}
return singleton;
}
private AkkaStarter2(){
sub = new Jedis(REDISHOST, REDISPORT);
akkaListener = new AkkaListener();
}
public void run() {
//blocking
sub.psubscribe(akkaListener, AKKAPREFIX + "*");
}
class AkkaListener extends JedisPubSub {
....
public void onPMessage(String pattern, String akkaChannel,String jsonSer) {
...
}
}
Thanks.
ermmm, the below solves it all. Indeed it was a Jedis thing
private AkkaStarter2(){
//0 specifying no timeout.. Overlooked this 100 times
sub = new Jedis(REDISHOST, REDISPORT,0);
akkaListener = new AkkaListener();
}