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.
Related
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 have a webservice deployed on a weblogic server. Whenever any client instance hits that webservice, I have to store the clients details and send mail to the client every 24 hours until the client takes the required action.
So in order to send mail every 24 hours, I've written a timer code, that should call the method to send mail every 24 hours.
My question is : Since the code is on server, And there can be 100s of clients that will hit my webservice and start their own timer instance. So does having these multiple timer instance(say 100 or more) affect the server performance?
If yes, please suggest an alternative code I can use to trigger mails sending every 24 hours after the webservice is hit.
Update - My Code
public static final Map<String, Timer> userDeactivationPendingMap = new HashMap();
#GET
#Path("/check-deactivation-status/{username}")
#Produces(MediaType.APPLICATION_JSON)
public String checkDeactivationStatus(#PathParam("username") final String username) {
String returnJsonString = "Email has been sent to IProc team to take further actions on it.";
Timer timer = new Timer();
TimerTask dailyTask = new TimerTask() {
#Override
public void run() {
hitEmailSendingApi(username, "abc#test.com");
}
};
// schedule the task to run starting now and then every day...
timer.schedule(dailyTask, 0l, 1000 * 60 * 60 * 24);
userDeactivationPendingMap.put(username, timer);
return returnJsonString;
}
#Path("/initializeUserDeactivationRequest") #GET
#Produces(MediaType.TEXT_HTML)
public String deactivateUser(#QueryParam("username") String username) {
//code to deactivate user
//Cancelling timer
Timer timer = userDeactivationPendingMap.get(username);
timer.cancel();
return "<h4>User Deactivated Successfully!!<h4>";
}
private void hitEmailSendingApi(String username, String iprocTeamMailAddress) {
String domain = RequestFilter.getRequest().getRequestURL().toString();
String contextPath = RequestFilter.getRequest().getContextPath();
String serverURL = domain.substring(0, domain.indexOf(contextPath));
String servletPath = RequestFilter.getRequest().getServletPath();
serverURL = serverURL + contextPath + servletPath;
EmailSender.sendEmail(iprocTeamMailAddress, "Action Required: Clear User's Pending Requisitions for Account Deactivation", "Hi Team"
+ ",\n\n A new request for user deactivation has been raised by " + username + ".\n\n"
+ "Once all the requisitions are cleared, please press on below link for deactivating the user.\n"
+ serverURL + "/deactivate-account/initializeUserDeactivationRequest?username=" + (username));
}
I've a problem with repeated tasks.
Basically, I'm working on service, which sends sms and check response for a minute. If response received, I update textview with success message otherwise fail.
My send sms service works ok, but I am stuck at receiving the sms.
I call send sms and check sms like this:
sendSms("6617", "Test") // it works;
readSms.run() // it works too;
if (message.equals("desired sms"){ // it doesn't wait read sms to finish
updateTextView("Success");
}
else{
updateTextView("Fail");
}
Here is readSms:
Runnable readSms = new Runnable(){
receivedMessage = "";
#Override
public void run() {
try {
//..checking sms..//
if (smsreceived) {message=receivedMessage;}
} finally {
mHandler.postDelayed(readSms, mInterval);
}
}
};
How can I make readSms to wait 60 seconds timeout with 1 second interval. If sms received, I should update textview with success, if not I'll wait until timeout and set textview with fail.
What you can do is:
Create a thread pool
Submit your task as a Callable to the thread pool
Wait a minute for a result
Create your thread pool using Executors like this for example:
// Create a thread pool composed of only one thread in this case
ExecutorService executor = Executors.newSingleThreadExecutor();
Submit your task as a Callable
Future<String> result = executor.submit(new Callable<String>(){
#Override
public String call() {
try {
//..checking sms..//
if (smsreceived) {return receivedMessage;}
return null;
} finally {
mHandler.postDelayed(readSms, mInterval);
}
}
});
Wait a minute for a result
try {
String receivedMessage = result.get(1, TimeUnit.MINUTES);
} catch (TimeoutException e) {
// ok let's give up
}
If the result cannot be retrieved within 1 minute the get method will throw a TimeoutException.
NB: The thread pool must not be created at each call, it must be created once for all in your class in order to reuse it at each call.
I have generated a request for web services. I need to do do a check on my call. If the response is not returned within 5 seconds, another request will be shooted.
Pseudo Code :
webServiceClass response = xyz.getData();
If the response is not obtained in 5 seconds - send another request CheckData() to web services.This should be done for a maximum of 5 times.
I need to do this without using threads.
Try something like this (not tested but should give you the idea):
final MultiThreadedHttpConnectionManager httpConnections = new MultiThreadedHttpConnectionManager();
final HttpConnectionManagerParams connParams = manager.getParams();
final HttpClient httpClient = new HttpClient(manager);
final int connectionTimeout = 5000;
connParams.setConnectionTimeout(connectionTimeout);
try
{
// your web service call goes here
}
catch(ConnectTimeoutException cte)
{
if (isLoggingError())
{
logError(cte.getMessage());
}
}
catch(IOException ioe)
{
if (isLoggingError())
{
logError(ioe.getMessage());
}
}
finally
{
// make sure we always release the connection
method.releaseConnection();
}
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.