One of my apps uses a lot of HTTP requests to communicate with its back-end.
I use 2 different implementations to perform these requests:
The library Volley for most cases
A combination of AsyncTask and DefaultHttpClient for few cases
Most of the time, everything works well. But sometimes I have a bunch of network exceptions raised and shown into Crashlytics:
java.net.UnknownHostException: Unable to resolve host "mydomain.com": No address associated with hostname
Caused by: libcore.io.GaiException: getaddrinfo failed: EAI_NODATA (No address associated with hostname)
com.android.volley.ServerError
at com.android.volley.toolbox.BasicNetwork.performRequest(BasicNetwork.java:175)
at com.android.volley.NetworkDispatcher.run(NetworkDispatcher.java:110)
With a bit of research, I found that this is supposed to happen when the device has a really bad 3g/4g or behind a VPN/subnetwork so it can't reach my website.
How do I make sure the device is really connected to internet?
I actually perform these requests only if this function return true:
public static boolean isOnline(Context ctx) {
ConnectivityManager cm = (ConnectivityManager) ctx.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
if (netInfo != null && netInfo.isConnectedOrConnecting()) {
return true;
}
return false;
}
Or should I just let it go and assume it is normal to get up to few hundreds of these warning per month?
In order to see if you have internet you have to do something more than check if you have a network connection. Because if your connected to a slow network, captive portal or a VPN you have a connection to the network but no actual internet or usable internet.
That's why you still need to check if you have internet/usable internet before you make a HTTP request by adding a simple ping to a server or Google (Because Google is up 99,99% of the time). You can also do it periodically or when you catch the first exception, that's up to you.
public Boolean isInternet() {
try {
Process process = java.lang.Runtime.getRuntime().exec("ping -c 1 www.google.com");
int returnVal = process.waitFor();
boolean reachable = (returnVal==0);
return reachable
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return false;
}
You can also use another method but the general idea is the same use something you know is almost always online and check if you can reach it.
However keep handling exceptions, because there is no way to always catch it and having a back up way of handling things can't hurt
How do I make sure the device is really connected to internet?
You have found out. That's what the errors are telling you.
How do I make sure the device is really connected to internet? I actually perform these requests only if this function return true:
I'm not in favour of this sort of thing:
if it tests exactly the same things as the actual request does, it is (i) duplicated work and (ii) not done at the same time
if it doesn't test exactly the same things as the actual request, you are likely to get both false positives and false negatives
in all cases, it's an attempt to predict the future. It might fail now and the request succeed, or succeed now and the request fail.
you have to write the error handling code for the request anyway.
In general the best way to test whether any resource is available is just to try to use it in the normal way, and deal with any adverse consequences as and when they arise.
Or should I just let it go and assume it is normal to get up to few hundreds of these warning per month?
I wouldn't say ServerError is normal. It's possible that the server managed to send that to you over a fully functioning network, so it may be a server or client bug you need to investigate. Network outages on the other hand are 'normal' in any topology and technology.
Yes you should check internet availability before making an HTTP request, it saves a lot for you.
The code you should is very good and far better than "pinging" any domain.
But still in your case your condition isn't going to be sufficient, because the adapter is actually connected but you may not be able to connect to your server due to poor connection.
So you should still handle time-out and IO exceptions that might happen while you're executing your requests.
-- Set time out for your Httpclient -- and i think volley by default has a timeout.
Related
Advice please on connection management and retries with IMqttAsyncClient in Java
I see that connection options include auto-reconnection, which in the synchronous client only come into play when an initial connection has been made.
I don't see explicit documentation on the behaviour for IMqttAsyncClient is the initial connection fails. Am I required to have retry logic in my code for the initial connection?
So far it appears that when I attempt to connect as expected the failure callback fires. But then what am I supposed to do? Am I required to code some retry logic myself? In the later auto-reconnect scenario, retries occur. At first sight it appears that once the initial connection fails then that's it.
I have coded a retry in the failure callback
// my original connection method, re-used below from failure
... connect(... params ...) {
attempt connection using MqttAsyncClient.connect()
}
// callback
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
// log failure here
// User Context lets me know what we're trying to do
if ( "connecting".equals(asyncActionToken.getUserContext())
&& ( ! myShutdownRequested ) ) {
// log retrying and sleep a bit here
connect(); // calling original connect method again
}
}
explicit questions
Do I have responsibility for handling retries? Seems odd, given the auto-try capability, but so it goes.
In which case is it safe to call MqttAsyncClient.connect() from inside the failure callback?
I've failed to find explicit documentation on either point, and "did I try it" doesn't cover point 2. If there's a subtle race condition any problem might not show up immediately. So far it appears to work nicely ...
I'd like to listen on a websocket using akka streams. That is, I'd like to treat it as nothing but a Source.
However, all official examples treat the websocket connection as a Flow.
My current approach is using the websocketClientFlow in combination with a Source.maybe. This eventually results in the upstream failing due to a TcpIdleTimeoutException, when there are no new Messages being sent down the stream.
Therefore, my question is twofold:
Is there a way – which I obviously missed – to treat a websocket as just a Source?
If using the Flow is the only option, how does one handle the TcpIdleTimeoutException properly? The exception can not be handled by providing a stream supervision strategy. Restarting the source by using a RestartSource doesn't help either, because the source is not the problem.
Update
So I tried two different approaches, setting the idle timeout to 1 second for convenience
application.conf
akka.http.client.idle-timeout = 1s
Using keepAlive (as suggested by Stefano)
Source.<Message>maybe()
.keepAlive(Duration.apply(1, "second"), () -> (Message) TextMessage.create("keepalive"))
.viaMat(Http.get(system).webSocketClientFlow(WebSocketRequest.create(websocketUri)), Keep.right())
{ ... }
When doing this, the Upstream still fails with a TcpIdleTimeoutException.
Using RestartFlow
However, I found out about this approach, using a RestartFlow:
final Flow<Message, Message, NotUsed> restartWebsocketFlow = RestartFlow.withBackoff(
Duration.apply(3, TimeUnit.SECONDS),
Duration.apply(30, TimeUnit.SECONDS),
0.2,
() -> createWebsocketFlow(system, websocketUri)
);
Source.<Message>maybe()
.viaMat(restartWebsocketFlow, Keep.right()) // One can treat this part of the resulting graph as a `Source<Message, NotUsed>`
{ ... }
(...)
private Flow<Message, Message, CompletionStage<WebSocketUpgradeResponse>> createWebsocketFlow(final ActorSystem system, final String websocketUri) {
return Http.get(system).webSocketClientFlow(WebSocketRequest.create(websocketUri));
}
This works in that I can treat the websocket as a Source (although artifically, as explained by Stefano) and keep the tcp connection alive by restarting the websocketClientFlow whenever an Exception occurs.
This doesn't feel like the optimal solution though.
No. WebSocket is a bidirectional channel, and Akka-HTTP therefore models it as a Flow. If in your specific case you care only about one side of the channel, it's up to you to form a Flow with a "muted" side, by using either Flow.fromSinkAndSource(Sink.ignore, mySource) or Flow.fromSinkAndSource(mySink, Source.maybe), depending on the case.
as per the documentation:
Inactive WebSocket connections will be dropped according to the
idle-timeout settings. In case you need to keep inactive connections
alive, you can either tweak your idle-timeout or inject ‘keep-alive’
messages regularly.
There is an ad-hoc combinator to inject keep-alive messages, see the example below and this Akka cookbook recipe. NB: this should happen on the client side.
src.keepAlive(1.second, () => TextMessage.Strict("ping"))
I hope I understand your question correctly. Are you looking for asSourceOf?
path("measurements") {
entity(asSourceOf[Measurement]) { measurements =>
// measurement has type Source[Measurement, NotUsed]
...
}
}
This might be a simple problem, but I can't seem to find a good solution right now.
I've got:
OldApp - a Java application started from the command line (no web front here)
NewApp - a Java application with a REST api behind Apache
I want OldApp to call NewApp through its REST api and when NewApp is done, OldApp should continue.
My problem is that NewApp is doing a lot of stuff that might take a lot of time which in some cases causes a timeout in Apache, and then sends a 502 error to OldApp. The computations continue in NewApp, but OldApp does not know when NewApp is done.
One solution I thought of is fork a thread in NewApp and store some kind of ID for the API request, and return it to OldApp. Then OldApp could poll NewApp to see if the thread is done, and if so - continue. Otherwise - keep polling.
Are there any good design patterns for something like this? Am I complicating things? Any tips on how to think?
If NewApp is taking a long time, it should immediately return a 202 Accepted. The response should contain a Location header indicating where the user can go to look up the result when it's done, and an estimate of when the request will be done.
OldApp should wait until the estimate time is reached, then submit a new GET call to the location. The response from that GET will either be the expected data, or an entity with a new estimated time. OldApp can then try again at the later time, repeating until the expected data is available.
So The conversation might look like:
POST /widgets
response:
202 Accepted
Location: "http://server/v1/widgets/12345"
{
"estimatedAvailableAt": "<whenever>"
}
.
GET /widgets/12345
response:
200 OK
Location: "http://server/v1/widgets/12345"
{
"estimatedAvailableAt": "<wheneverElse>"
}
.
GET /widgets/12345
response:
200 OK
Location: "http://server/v1/widgets/12345"
{
"myProperty": "myValue",
...
}
Yes, that's exactly what people are doing with REST now. Because there no way to connect from server to client, client just polls very often. There also some improved method called "long polling", when connection between client and server has big timeout, and server send information back to connected client when it becomes available.
The question is on java and servlets ... So I would suggest looking at Servlet 3.0 asynchronous support.
Talking from a design perspective, you would need to return a 202 accepted with an Id and an URL to the job. The oldApp needs to check for the result of the operation using the URL.
The thread that you fork on the server needs to implement the Callable interface. I would also recommend using a thread pool for this. The GET url for the Job that was forked can check the Future object status and return it to the user.
I'm looking for best technique to verify internet over WiFi or Cell. Let's say you are connected to some AP but you don't now if internet exists.
Today I have 2 options by using HttpURLConnection:
Download file from cdn server
to send request to trust web page like google.com and get response 200.
Any other ways?
All suggestions would be appreciated.
On some level, 'ability to access internet endpoints' is equivalent to 'having internet access'. You could consider some algorithm:
for (Endpoint site : theEntireInternet) {
if (can connect to site) return true;
}
return false;
which will conclusively establish connectivity. In other words, being able to connect to any one site is sufficient positive proof, but theoretically you would need to enumerate every site to prove non-connectivity. In practice, checking a few major sites is obviously sufficient. Otherwise (without some sort of meta-information about networks, ISPs, etc; which is unavailable) there's no way to conclusively demonstrate "internet" connectivity other than... connecting to the internet.
Of course as you comment, checking various internet-based applications can't hurt either; it's just a different form of an equivalent technique.
See the Telephony Manager and it's getDataSate() method it has four state
DATA_DISCONNECTED
DATA_CONNECTING
DATA_CONNECTED
DATA_SUSPENDED
You can get the instance of telephony manager --
TelephonyManager tm = (TelephonyManager)getSystemService(Telephony_Service);
Here it is:
to see the state of the data connection on the cell network
and for the WIFI, I would use this public class WifiInfo. From there you can use getIpAddress() or getDetailedStateOf(...)
Hope it's helpful.
I´ve been looking for a good book or article about this topic but didnt find much. I didnt find a good example - piece of code - for a specific scenario. Like clients/server conversation.
In my application´s protocol they have to send/recieve messages. Like:
Server want to send a file to a client
Client can accpet or no,
if he accepts, server will send bytes over the same connection/socket.
The rest of my application all uses blocking methods, server has a method
Heres what I did:
Server method:
public synchronized void sendFile(File file)
{
//send messsage asking if I can send a file
//block on read, waiting for client responde
//if client answers yes, start sending the bytes
//else return
}
Client methods:
public void reciveCommand()
{
//read/listen for a command from socket
//if is a send file command handleSendFileCommand();
//after the return of handleSendFileCommand() listen for another command
}
public void handleSendFileCommand()
{
//get the file server want to send
//check if it already has the file
//if it already has, then send a command to the socket saying it already has and return
//else send a command saying server can send the file
//create a FileInputStream, recive bytes and then return method
}
I am 100% sure this is wrong because, there is no way server and clients would talk bidirecional, I mean, when server wants to send a command to a server, they have to follow an order of commands until that conversation is finished, only then, they can send/recive another sequence of commands. Thats why I made all methods that send requests synchronized
It didnt took me a lot of time to realize I need to study about design patterns for that kind of application...
I read about Chain of Responsibility design pattern but I dont get it how can I use it or another good design pattern in that situation.
I hope someone can help me with some code example-like.
Thanks in advance
synchronized keyword in Java means something completely different - it marks a method or a code block as a critical section that only single thread can execute at a time. You don't need it here.
Then, a TCP connection is bi-directional on the byte-stream level. The synchronization between the server and a client is driven by the messages exchanged. Think of a client (same pretty much applies to the server) as a state machine. Some types of messages are acceptable in the current state, some are not, some switch the node into different state.
Since you are looking into design patterns, the State pattern is very applicable here.