my question is on parse.com queries for Android and how to set a timeout if queries are taking too long to respond.
For example, I have a query where I am getting a list of strings from parse.com. If this query takes too long to be received from parse.com (say, ten seconds), I'd like the user to be able to cancel the query (with an on-screen pop-up, for example). Instead, the app crashes after 30+ seconds of waiting.
So, is there a way to set my own timeout for queries, then handle them appropriately?
Https is the protocol for connections with parse.
Http(s) allows full control of the following:
Socket timeout
getConnection timeout
connectionRequest timeout
In order to manipulate the headers, i know that with parse.com you can use the Rest API and then do anything u want with the headers in the builder....
public void create(int method, final String url, final String data) {
this.method = method;
this.url = url;
this.data = data;
if(method == GET){
this.config = RequestConfig.custom()
.setConnectTimeout(6 * 1000)
.setConnectionRequestTimeout(30 * 1000)
.setSocketTimeout(30 * 1000)
.build();
} else{
this.config = RequestConfig.custom()
.setConnectTimeout(6 * 1000)
.setConnectionRequestTimeout(30 * 1000)
.setSocketTimeout(60 * 1000)
.build();
}
this.context = HttpClientContext.create();
If you use only android sdk, then you will need docs at parse.com to figure out how ( or whether possible ) to set the http connection config listed above.
My solution was to use RxJava Observable.timer(long delay, java.util.concurrent.TimeUnit unit) method.
I declare a RxJava Subscription field, and then init it to an Observable.timer(20, TimeUnit.SECONDS) call, just before any Parse.InBackground() code.
Inside the Observable.timer() method, I invoke another method that'll throw a Java Exception within a try{...} block, and then handle the thrown exception within the following catch {...} block. What this does is have the Observable.timer() call invoke the exception-throwing method as soon as the set time (e.g. 20 seconds in the example above) is exhausted. By handling it in the catch {...} block, you can show a dialog/alert informing user that the operation has timed out.
Here's a code snippet showing this:
Subscription timeoutWatcher;
public void loginWithEmailAndPassword(#NonNull String email, #NonNull String password) {
timeoutWatcher = Observable.timer(10, TimeUnit.SECONDS).subscribe(aLong -> {
// Login timed out. Notify user to check Internet connection is chooppy.
throwNetworkException("Timeout! Your Internet connection is unstable and preventing your sign in from completing on time. Please try again.");
});
ParseUser.logInInBackground(email, password, (user, e) -> {
// if Parse operation completes before timeout, then unsubscribe from the Observable.timer() operation
timeoutWatcher.unsubscribe();
if (user != null) {
// Hooray! The user is logged in.
} else {
// Signup failed. Look at the ParseException to see what happened.
}
});
}
}
private void throwNetworkException(String exceptionMessage) {
try {
throw new NetworkErrorException(exceptionMessage);
} catch (NetworkErrorException e) {
// show alert dialog
}
}
Not the neatest piece of code, but it works for me.
Unfortunately, there is no way to specify a timeout for Parse requests.
Instead, you can catch the timeout exception & take necessary action
try{
...
}catch (ParseException e) {
String mesg = e.getMessage();
if(mesg!= null && mesg.contains("java.net.SocketTimeoutException")){
// Do something here...
}
}
Note: If you are using inBackground Parse methods, then you need to check for the exception in the callback method.
Related
My current Lambda function is calling a 3rd party web service Synchronously.This function occasionally times out (current timeout set to 25s and cannot be increased further)
My code is something like:
handleRequest(InputStream input, OutputStream output, Context context) throws IOException {
try{
response = calling 3rd party REST service
}catch(Exception e){
//handle exceptions
}
}
1)I want to custom handle the timeout (tracking the time and handling few milli seconds before actual timeout) within my Lambda function by sending a custom error message back to the client.
How can I effectively use the
context.getRemainingTimeInMillis()
method to track the time remaining while my synchronous call is running? Planning to call the context.getRemainingTimeInMillis() asynchronously.Is that the right approach?
2)What is a good way to test the timeout custom functionality ?
I solved my problem by increasing the Lambda timeout and invoking my process in a new thread and timing out the Thread after n seconds.
ExecutorService service = Executors.newSingleThreadExecutor();
try {
Runnable r = () ->{
try {
myFunction();
} catch (Exception e) {
e.printStackTrace();
}
};
f = service.submit(r);
f.get(n, TimeUnit.MILLISECONDS);// attempt the task for n milliseconds
}catch(TimeoutException toe){
//custom logic
}
Another option is to use the
readTimeOut
property of the RestClient(in my case Jersey) to set the timeout.But I see that this property is not working consistently within the Lambda code.Not sure if it's and issue with the Jersey client or the Lambda.
You can try with cancellation token to return custom exceptions with lambda before timeout.
try
{
var tokenSource = new CancellationTokenSource(TimeSpan.FromMinutes(1)); // set timeout value
var taskResult = ApiCall(); // call web service method
while (!taskResult.IsCompleted)
{
if (tokenSource.IsCancellationRequested)
{
throw new OperationCanceledException("time out for lambda"); // throw custom exceptions eg : OperationCanceledException
}
}
return taskResult.Result;
}
catch (OperationCanceledException ex)
{
// handle exception
}
I have this code for a HTTP GET method:
#Override
public Cert get(Representation entity) {
// ...
Cert cert = ct.fetchCertificate(Arrays.asList(domains));
return cert;
}
It's a certificate generator that returns the serialized Cert object into the client.
And inside the fetchCertificate method is a Thread.sleep method that causes the entire servlet/web application to halt until the method returns, causing the whole web application not able to response to additional HTTP requests:
// Poll for the challenge to complete.
try {
int attempts = 20;
while (challenge.getStatus() != Status.VALID && attempts-- > 0) {
LOG.info("CHALLENGE ATTEMPTS: " + attempts);
// Did the authorization fail?
if (challenge.getStatus() == Status.INVALID) {
throw new AcmeException("Challenge failed... Giving up.");
}
// Wait for a few seconds
Thread.sleep(5000L);
// Then update the status
challenge.update();
}
} catch(Exception e) {
// ...
}
In RxJava terms what is the best way to achieve this same functionality but without blocking the application.
You need to put this Whole HTTP request calling and sleep inside a secondary thread. It seems it blocks the main thread.
I'm integrating with a payments processor and am trying to deal with the scenario where:
user clicks pay and a request is made to our server
our server makes a request to the payment processor
there is a significant delay on the payment processor side
after a certain threshold e.g. 60 seconds, we alert the user that their payment was unsuccessful
after 70 seconds the payment processor returns a successful response.
So I need to start an API call to the payment processor from within the HTTP call from the UI, then if it takes more than 60 seconds, end the HTTP call and return an error to the user, then if the API call to the payment processor eventually succeeds (say after 70 seconds), send an email to the admin team.
I'm thinking of something like this:
import javax.ws.rs.client.*;
import java.util.Timer;
import java.util.TimerTask;
...
boolean overThreshold = false;
int timeout = 60; // seconds
TimerTask task = new TimerTask() {
#Override
public void run() {
overThreshold = true;
// return a message to user here saying their payment could not be processed
}
};
new Timer(true).schedule(task, timeout * 1000);
Client client = ClientBuilder.newClient();
WebTarget webTarget
= client.target({url of payment processor});
Invocation.Builder builder = webTarget.request()
.header(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON);
final Response response = builder.post(Entity.json(new Gson().toJson(request)));
if (overThreshold) {
// send alert email here
}
There are a few problems, e.g. the run() method has void return value, error with overThreshold as being accessed from a inner class. Is there a more elegant way of doing this?
Using Future.get(timeout) from an ExecutorService should handle this quite cleanly.
For example:
ExecutorService executor = Executors.newCachedThreadPool();
// ... set up builder as before ...
Future<Response> responseFuture = executor.submit(
() -> builder.post(Entity.json(new Gson().toJson(request))));
try {
Response response = responseFuture.get(timeout, TimeUnit.SECONDS);
// return normal response here
} catch (TimeoutException ex) {
executor.submit( () -> {
Response lateResponse = responseFuture.get();
// send overThreshold alert email here
// Dummy return - prefer Callable to Runnable here for exception handling
return null;
} );
// return a message to user here saying their payment could not be processed
}
The choice of ExecutorService could be tuned to fit, or equally be a shared thread pool elsewhere in the application.
I am relatively new to App Engine. I do not understand how to asynchronously make an HTTP request with Java. I would have thought that this was a very simple matter using Thread and Runnable. But it seems that App Engine does not permit their use.
public Hashtable someApiMethod(..) {
SomeEntity entity = new SomeEntity(..);
ObjectifyService.ofy().save().entity(entity).now();
makeSomeHttpRequest(entity);
return launchResponse;
}
My question is this: how do I implement the method makeSomeHttpRequest(..) such that it returns without waiting for the URLFetchService.fetchAsync to return. I have tried the following without success:
protected void makeSomeHttpRequest(SomeEntity entity) {
URLFetchService fetcher = URLFetchServiceFactory.getURLFetchService();
try {
URL url = new URL("https://www.example.com");
Future future = fetcher.fetchAsync(url);
HTTPResponse response = (HTTPResponse) future.get();
byte[] content = response.getContent();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bos.write(content);
String responseString = new String(bos.toByteArray());
int responseCode = response.getResponseCode();
// Here I will do something with the responseCode and responseString
if (responseCode == 200) entity.someValue = responseString;
} catch (IOException e) {
// handle this
} catch (InterruptedException e) {
// handle this
} catch (ExecutionException e) {
// handle this
}
}
Really what I am trying to do is perform this HTTP request without forcing the method someApiMethod to wait for the response.
Few things:
First. Future doesn't work this way. Method .get waits for result of Feature execution, so basically you're stopping current thread until other thread finishes its execution. You're making it synchronous, it doesn't make any sense. Usually you call .get much later, when all other work in current thread is finished
Second. Threads in Appengine are limited to current request, you have to complete all async processing during current request. So updating an entity in such way doesn't make much sense, it's still bounded to current request. I mean in your case makeSomeHttpRequest(entity); should work faster than return launchResponse;
What you really need is to send this data to TaskQueue and make processing of SomeEntity entity from there (but don't send entity itself, just send ID and load by id from queue task). Basically it's going to be a new request handler (servlet/controller/etc) that should load entity by id, execute makeSomeHttpRequest (synchronously) and return http status 200.
See TaskQueue docs: https://cloud.google.com/appengine/docs/java/taskqueue/
You need Push Queue most likely: https://cloud.google.com/appengine/docs/java/taskqueue/overview-push
I'm using a variation of the example at http://svn.apache.org/repos/asf/activemq/trunk/assembly/src/release/example/src/StompExample.java to receive message from a queue. What I'm trying to do is to keep listening to a queue and perform some action upon reception of a new message. The problem is that I couldn't find a way to register a listener to any of the related objects. I've tried something like:
public static void main(String args[]) throws Exception {
StompConnection connection = null;
try {
connection = new StompConnection();
connection.open("localhost", 61613);
connection.connect("admin", "activemq");
connection.subscribe("/queue/worker", Subscribe.AckModeValues.AUTO);
while (true) {
StompFrame message = connection.receive();
System.out.println(message.getBody());
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
but this doesn't work as a time out occurs after a few seconds (java.net.SocketTimeoutException: Read timed out). Is there anything I can do to indefinitely listen to this queue?
ActiveMQ's StompConnection class is a relatively primitive STOMP client. Its not capable of async callbacks on Message or for indefinite waits. You can pass a timeout to receive but depending on whether you are using STOMP v1.1 it could still timeout early if a heart-beat isn't received in time. You can of course always catch the timeout exception and try again.
For STOMP via Java you're better off using StompJMS or the like which behaves like a real JMS client and allows for async Message receipt.
#Tim Bish: I tried StompJMS, but couldn't find any example that I could use (maybe you can provide a link). I 'fixed' the problem by setting the timeout to 0 which seems to be blocking.
even i was facing the same issue.. you can fix this by adding time out to your receive() method.
Declare a long type variable.
long waitTimeOut = 5000; //this is 5 seconds
now modify your receive function like below.
StompFrame message = connection.receive(waitTimeOut);
This will definitely work.