Signal R taking around 1 minute to connect to Hub in mobile network Xamarin forms - xamarin.forms

Below is my code to connect to the hub.
I used the below code for connecting the hub and send a message.
public ChatService(){
connection = new HubConnection(Services.ServerConstant.BaseUrl);
proxy = ChatServices._connection.CreateHubProxy("HubName");
}
//to start connection
Void async Start(){
var http = new Microsoft.AspNet.SignalR.Client.Http.DefaultHttpClient();
await _connection.Start(new WebSocketTransportLayer(http));
}
//For Connection
Void SendMessage(){
chatServices = DependencyService.Get<IChatServices>();
chatServices.Connect();
connection.Start();
await connection.Send("Test");
}

You are recreating connection to hub every time you send the message. That's wrong approach. Instead you should check connection status and reconnect only in case the connection is lost.
Example
private async Task CheckConnection()
{
if (connection.State == ConnectionState.Connected)
{
return;
}
try
{
await connection.Start();
await proxy.Invoke("Connect");
}
catch (Exception ex)
{
// your exception handler goes here
}
}

Related

Use a message for a topic in Confluent.Kafka when consumer run

I'm using Confluent.Kafka(1.4.4) in a .netCore project as a message broker. In the startup of the project I set only "bootstrapservers" to the specific servers which were in the appSetting.json file and I produce messages in an API when necessary with the code below in related class:
public async Task WriteMessage<T>(string topicName, T message)
{
using (var p = new ProducerBuilder<Null, string>(_producerConfig).Build())
{
try
{
var serializedMessage= JsonConvert.SerializeObject(message);
var dr = await p.ProduceAsync(topicName, new Message<Null, string> { Value = serializedMessage });
logger.LogInformation($"Delivered '{dr.Value}' to '{dr.TopicPartitionOffset}'");
}
catch (ProduceException<Null, string> e)
{
logger.LogInformation($"Delivery failed: {e.Error.Reason}");
}
}
}
I have also added the following code In the consumer solution :
public async Task Run()
{
using (var consumerBuilder = new ConsumerBuilder<Ignore, string>(_consumerConfig).Build())
{
consumerBuilder.Subscribe(new List<string>() { "ActiveMemberCardForPanClubEvent", "CreatePanClubEvent", "RemovePanClubEvent"
});
CancellationTokenSource cts = new CancellationTokenSource();
Console.CancelKeyPress += (_, e) =>
{
e.Cancel = true; // prevent the process from terminating.
cts.Cancel();
};
try
{
while (true)
{
try
{
var consumer = consumerBuilder.Consume(cts.Token);
if (consumer.Message != null)
{
using (LogContext.PushProperty("RequestId", Guid.NewGuid()))
{
//Do something
logger.LogInformation($"Consumed message '{consumer.Message.Value}' at: '{consumer.TopicPartitionOffset}'.");
await DoJob(consumer.Topic, consumer.Message.Value);
consumer.Topic.Remove(0, consumer.Topic.Length);
}
}
else
{
logger.LogInformation($"message is null for topic '{consumer.Topic}'and partition : '{consumer.TopicPartitionOffset}' .");
consumer.Topic.Remove(0, consumer.Topic.Length);
}
}
catch (ConsumeException e)
{
logger.LogInformation($"Error occurred: {e.Error.Reason}");
}
}
}
catch (OperationCanceledException)
{
// Ensure the consumer leaves the group cleanly and final offsets are committed.
consumerBuilder.Close();
}
}
}
I produce a message and when the consumer project is run everything goes perfectly and the message is being read in the consumer solution.
The problem is raised when the consumer project is not run and I queue a message in the API with the message producer in API. After running consumers there is not any valid message for that topic that it's message is being produced.
I am familiar with and have experiences with message brokers and I know that by sending a message it will be on the bus until it is being used but I don't understand why it doesn't work with Kafka in this project.
The default setting for the "auto.offset.reset" Consumer property is "latest".
That means (in the context of no offsets being written yet) if you write a message to some topic and then subsequently start the consumer, it will skip past any messages written before the consumer was started. This could be why your consumer is not seeing the messages queued by your producer.
The solution is to set "auto.offset.reset" to "earliest" which means that the consumer will start from the earliest offset on the topic.
https://docs.confluent.io/current/installation/configuration/consumer-configs.html#auto.offset.reset

Jersey2 Client reuse not working AsyncInvoker

I am trying to reuse a Jersey2(Jersey 2.16) Client for async invocation. However after 2 requests, I see that the threads going into a waiting state, waiting on a lock. Since client creation is an expensive operation, I am trying to reuse the client in the async calls. The issue occurs only with ApacheConnectorProvider as the connector class. I want to use ApacheConnectorProvider, as I need to use a proxy and set SSL properties and I want to use PoolingHttpClientConnectionManager.
The sample code is given below:
public class Example {
Integer eventId = 0;
private ClientConfig getClientConfig()
{
ClientConfig clientConfig = new ClientConfig();
ApacheConnectorProvider provider = new ApacheConnectorProvider();
clientConfig.property(ClientProperties.REQUEST_ENTITY_PROCESSING,RequestEntityProcessing.BUFFERED);
clientConfig.connectorProvider(provider);
return clientConfig;
}
private Client createClient()
{
Client client = ClientBuilder.newClient(getClientConfig());
return client;
}
public void testAsyncCall()
{
Client client = createClient();
System.out.println("Testing a new Async call on thread " + Thread.currentThread().getId());
JSONObject jsonObject = new JSONObject();
jsonObject.put("value", eventId++);
invoker(client, "http://requestb.in/nn0sffnn" , jsonObject);
invoker(client, "http://requestb.in/nn0sffnn" , jsonObject);
invoker(client, "http://requestb.in/nn0sffnn" , jsonObject);
client.close();
}
private void invoker(Client client, String URI, JSONObject jsonObject)
{
final Future<Response> responseFuture = client.target(URI)
.request()
.async()
.post(Entity.entity(jsonObject.toJSONString(), MediaType.TEXT_PLAIN));
try {
Response r = responseFuture.get();
System.out.println("Response is on URI " + URI + " : " + r.getStatus());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String args[])
{
Example client1 = new Example();
client1.testAsyncCall();
return;
}
}
The response I see is:
Testing a new Async call on thread 1
Response is on URI http://requestb.in/nn0sffnn : 200
Response is on URI http://requestb.in/nn0sffnn : 200
On looking at the thread stack, I see the following trace:
"jersey-client-async-executor-0" prio=6 tid=0x043a4c00 nid=0x56f0 waiting on condition [0x03e5f000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x238ee148> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2043)
at org.apache.http.pool.PoolEntryFuture.await(PoolEntryFuture.java:133)
at org.apache.http.pool.AbstractConnPool.getPoolEntryBlocking(AbstractConnPool.java:282)
at org.apache.http.pool.AbstractConnPool.access$000(AbstractConnPool.java:64)
at org.apache.http.pool.AbstractConnPool$2.getPoolEntry(AbstractConnPool.java:177)
at org.apache.http.pool.AbstractConnPool$2.getPoolEntry(AbstractConnPool.java:170)
Can someone give me a suggestion as to how to reuse Client objects for async requests and may be how to get over this issue as well.

ASP.NET close connection before sending all websocket data to client

I wrote a simple asp.net websocket handler as a gateway between a remote data processing server and clients.
I tested in my local machine (win8, IIS EXPRESS 8) and everything worked well. But in azure website, ASP.NET closes connection before sending all websocket data to client.
Following is my data transfer code:
internal class WebSocketStreamTransfer{
public WebSocketStreamTransfer(CancellationToken disconnectionToken){
DisconnectionToken = disconnectionToken;
}
private CancellationToken DisconnectionToken{
get;
set;
}
public async Task AcceptWebSocketConnection(WebSocketContext context) {
if (context == null)
throw new ArgumentNullException("context");
WebSocket websocket = context.WebSocket;
if (websocket == null)
throw new SocksOverHttpException("Null websocket");
using(IConnection conn = ConnectionManagerFactory.ConnectionManager.CreateConnection(Guid.NewGuid().ToString())) {
try {
DisconnectionToken.Register(conn.Close);
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>(null);
await Task.WhenAny(SendDataToRemoteServer(conn, websocket, DisconnectionToken, tcs), SendDataToClient(conn, websocket, DisconnectionToken, tcs.Task));
} catch(Exception e) {
Logger.LogException(e);
}
}
}
internal static async Task SendDataToRemoteServer(IConnection conn, WebSocket websocket, CancellationToken cancelToken, TaskCompletionSource<bool> tcs) {
try {
ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[ApplicationConfiguration.GetDefaultBufferSize()]);
while (IsConnected(conn, cancelToken, websocket)) {
WebSocketReceiveResult result = await websocket.ReceiveAsync(buffer, cancelToken);
if (websocket.State == WebSocketState.Open) {
if (result.MessageType == WebSocketMessageType.Binary) {
if (result.Count > 0) {
if (IsConnected(conn, cancelToken, websocket)) {
int numRead = await conn.SendData(buffer.Array, 0, result.Count, cancelToken);
if (numRead > 0) {
tcs.TrySetResult(true); // Notify SendDataToClient can continue
}else{
Logger.LogError("Client not send enough data for remote connection built");
return;
}
} else {
Logger.LogInformation("SendDataToRemoteServer: Cancel send data to remote server due to connection closed");
}
} else
Logger.LogInformation("Receive empty binary message");
} else if (result.MessageType == WebSocketMessageType.Text) {
Logger.LogError("Receive unexpected text message");
return;
} else {
Logger.LogInformation("Receive close message");
await websocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Close Connection", cancelToken);
return;
}
} else {
Logger.LogInformation("SendDataToRemoteServer: WebSocket connection closed by client");
return;
}
}
}finally{
tcs.TrySetResult(true);
}
}
internal static async Task SendDataToClient(IConnection conn, WebSocket websocket, CancellationToken cancelToken, Task connectedTask) {
await connectedTask;
while (IsConnected(conn, cancelToken, websocket)) {
byte[] data = await conn.ReceiveData(cancelToken);
if (data.Length <= 0) {
Logger.LogInformation("SendDataToClient: Get empty data from remote server");
return;
}
if (IsConnected(conn, cancelToken, websocket)) {
await websocket.SendAsync(new ArraySegment<byte>(data), WebSocketMessageType.Binary, true, cancelToken);
} else {
Logger.LogInformation("SendDataToClient: Cancel send data to client due to connection closed");
}
}
}
internal static bool IsConnected(IConnection conn, CancellationToken cancelToken, WebSocket websocket) {
bool socketConnected = websocket.State == WebSocketState.Open;
return socketConnected && conn.Connected && !cancelToken.IsCancellationRequested;
}
}
Problem scenario:
SendDataToRemoteServer waiting for client data and client has not data to send yet
SendDataToClient receive empty data from remote server, means remote server start closing connection. So finish SendDataToClient
AcceptWebSocketConnection finish because Task.WhenAny(SendDataToRemoteServer(conn, websocket, DisconnectionToken, tcs), SendDataToClient(conn, websocket, DisconnectionToken, tcs.Task))
Expect ASP.NET send all data before close tcp connection but ASP.NET close connection immediately (azure).
A WebSocket message can be split in different frames. You are not checking if the message is completed. The code for sending information form a WS connection to other should look like this:
WebSocketReceiveResult result = null;
do
{
result = await source.ReceiveAsync(buffer, CancellationToken.None);
var sendBuffer = new ArraySegment<Byte>(buffer.Array, buffer.Offset, result.Count);
await target.SendAsync(sendBuffer, result.MessageType, result.EndOfMessage, CancellationToken.None);
}
while (!result.EndOfMessage);
You have to check the EndOfMessage property, and continue reading while the message is not completed.
It works in your local computer because locally you are no affected by the buffering in the same way, or because the messages you were trying were smaller.
await Task.WhenAny waits for any task to be completed. does not wait for the SendDataToClient task to be complete when SendDataToRemoteServer task is completed.
you need change
await Task.WhenAny(SendDataToRemoteServer(conn, websocket, DisconnectionToken, tcs), SendDataToClient(conn, websocket, DisconnectionToken, tcs.Task));
to
await Task.WhenAll(SendDataToRemoteServer(conn, websocket, DisconnectionToken, tcs), SendDataToClient(conn, websocket, DisconnectionToken, tcs.Task));
With a small sample:
async Task t1()
{
await Task.Delay(1000);
}
async Task t2()
{
await Task.Delay(2000);
}
Stopwatch watch = new Stopwatch();
watch.Start();
await Task.WhenAny(t1(), t2());
watch.Stop();
Debug.WriteLine("total milliseconds {0}", watch.ElapsedMilliseconds); // total milliseconds 1007
Stopwatch watch = new Stopwatch();
watch.Start();
await Task.WhenAll(t1(), t2());
watch.Stop();
Debug.WriteLine("total milliseconds {0}", watch.ElapsedMilliseconds); // total milliseconds 2009

How to call HTTP URL using wifi in J2ME code for BlackBerry 5.0 and above?

I am calling a web service from BlackBerry using J2ME code. When I try to open a connection using HttpConnection, it is checking only the GPRS connection. Now, I want to check the Wi-Fi connection and call a webservice through Wi-Fi.
The following code is my connection section. How to change the code for a Wi-Fi connection?
public boolean HttpUrl()
{
HttpConnection conn = null;
OutputStream out = null;
String url = "http://www.google.com";
try
{
conn = (HttpConnection) new ConnectionFactory().getConnection(url).getConnection();
if (conn != null)
{
conn.setRequestMethod(HttpConnection.POST);
conn.setRequestProperty("Content-Length", "application/x-www-form-urlencoded");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setRequestProperty("User-Agent", "Profile/MIDP-2.0 Configuration/CLDC-1.0");
}
}
catch (Exception e)
{
return false;
}
finally
{
try
{
out.close();
}
catch (Exception e2)
{
}
}
//Only if exception occurs, we close the connection.
//Otherwise the caller should close the connection himself.
try
{
conn.close();
}
catch (Exception e1)
{
}
return true;
}
Check this way:
HttpConnection conn = null;
String URL = "http://www.myServer.com/myContent;deviceside=true;interface=wifi";
conn = (HttpConnection)Connector.open(URL);
source
Making Connections
Rafael's answer will certainly work if you know you'll only be using Wi-Fi.
However, if you only need to support BlackBerry OS 5.0 - 7.1, I would recommend that you do use the ConnectionFactory. Normally, you will not limit your code to only using one transport. You'll normally support (almost) any transport the device has, but you may want to code your app to choose certain transports first.
For example,
class ConnectionThread extends Thread
{
public void run()
{
ConnectionFactory connFact = new ConnectionFactory();
connFact.setPreferredTransportTypes(new int[] {
TransportInfo.TRANSPORT_TCP_WIFI,
TransportInfo.TRANSPORT_BIS_B,
TransportInfo.TRANSPORT_MDS,
TransportInfo.TRANSPORT_TCP_CELLULAR
});
ConnectionDescriptor connDesc;
connDesc = connFact.getConnection("http://www.google.com");
if (connDesc != null)
{
HttpConnection httpConn;
httpConn = (HttpConnection)connDesc.getConnection();
try
{
// TODO: set httpConn request method and properties here!
final int iResponseCode = httpConn.getResponseCode();
UiApplication.getUiApplication().invokeLater(new Runnable()
{
public void run()
{
Dialog.alert("Response code: " +
Integer.toString(iResponseCode));
}
});
}
catch (IOException e)
{
System.err.println("Caught IOException: "
+ e.getMessage());
}
}
}
}
will choose the Wi-Fi transport if Wi-Fi is available, but use the GPRS connection if it isn't. I think this is generally considered best practice for the 5.0+ devices.
Request Properties
This code
conn.setRequestProperty("Content-Length", "application/x-www-form-urlencoded");
is not right. Content-Length should be the size, in bytes, of your HTTP POST parameters. See an example here.
Threading
Remember that making network connections is slow. Do not block the user interface by running this code on the main/UI thread. Put your code into a background thread to keep the UI responsive while you request remote content.

How to handle timeout of AsynchronousResponse object in RestEasy

i am implementing a jax-rs service with RestEasy on JBoss AS 7.1.2 an i would like to use asynchronous HTTP processsing as described here: http://docs.jboss.org/resteasy/docs/1.0.0.GA/userguide/html/Asynchronous_HTTP_Request_Processing.html
For thr AsynchronousResponse I define a timeout of 10 seconds. When this period expires, the request is responded with a 200 OK and an empty body. I would like to modify this behaviour so i need to be notified about the timeout event.
In my solution, I would like to handle the timeout event in a NotificationManager object, which keeps the AsycnhronousResponse for the time being. Please see the code below for details.
So far, i could not figure out how to do that. Does anyone have more experience with the RestEasy Asynchronous HTTP processing?
#POST
#Path("/blabla")
#Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
#Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public void subscribeLongPolling (
final #Suspend(10000) AsynchronousResponse response,
JAXBElement<LongPollingRequestParameters> rqParam,
#Context HttpServletRequest req) throws Exception {
//do some stuff with req
Thread t = new Thread("ThreadSubscribeTo:" + channelID)
{
#Override
public void run() {
//hand over to Notification Manager to return notifications in case some exist
try {
NotificationManager nm = new NotificationManager();
nm.setAsyncResponseObject(response);
logger.info("Response object registered in NotificationManager");
}catch (Exception e){
e.printStackTrace();
}
}
};
t.start();
logger.info("Releasing Thread");
}
public class NotificationManager {
private AsynchronousResponse response;
private NotificationList nList;
public synchronized void setAsyncResponseObject(AsynchronousResponse response) {
this.response = response;
if (nList.getAny().size() > 0) {
logger.info("Stored notification send to web client: " + nList.getAny().get(0).toString());
sendNotification(nList.getAny().remove(0));
}
}
public synchronized void sendNotification(Object message){
if (response != null){
logger.info("Response object found. Send notification immediately: " + message.toString());
Response responseObject = Response.ok(message, MediaType.APPLICATION_XML).build();
response.setResponse(responseObject);
response = null;
}else{
logger.info("Response object not found notification will be stored");
addNotification(message);
}
}
}
Thanks in advance,
Alex

Resources