Estoy integración con un procesador de pagos y estoy tratando de hacer frente a la situación en la que:
- pagan usuario hace clic y se hace una petición a nuestro servidor
- nuestro servidor hace una petición al procesador de pagos
- hay un retraso significativo en el lado procesador de pagos
- después de un cierto umbral, por ejemplo, 60 segundos, se alerta al usuario de que su pago no tuvo éxito
- después de 70 segundos, el procesador de pagos devuelve una respuesta exitosa.
Así que necesito para iniciar una llamada a la API al procesador de pagos desde la llamada HTTP desde la interfaz de usuario, a continuación, si se tarda más de 60 segundos, finalizar la llamada HTTP y devolver un error al usuario, a continuación, si la llamada API para el pago procesador finalmente tiene éxito (por ejemplo después de 70 segundos), envíe un correo electrónico al equipo de administración.
Estoy pensando en algo como esto:
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
}
Hay algunos problemas, por ejemplo, el run()
método tiene valor de retorno vacío, error con overThreshold
como que se accede a partir de una clase interna. ¿Hay una manera más elegante de hacer esto?
Usando Future.get (tiempo de espera) desde una ExecutorService debe manejar esto muy limpiamente.
Por ejemplo:
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
}
La elección del ExecutorService
podría ser sintonizado para encajar, o igualmente ser un grupo de subprocesos en la aplicación compartida en otro lugar.