Question

In my payment processing service I have two different webservice calls. First call to get customer's details and second call to payment gateway service for payment processing. These calls are not dependant on each other and can be called in any order.

Payment gateway call configured with 30 seconds timeout and customer detail call with 10 seconds. Currently calling them synchronously takes 40 seconds (30 + 10).

I want these calls to be made asynchronously for the performance reason. Calling them asynchronously will save 10 seconds processing as when payment gateway is processing the concurrent call to the customer details could be completed in the mean time.

How to implement this in java elegantly?

Was it helpful?

Solution 2

For example, you can do this with ExecutorService + Callable.

Make two classes that implements Callable interface, create executor service, add two tasks to service and get features. From futures get result of calls.

OTHER TIPS

This is what I did

try {
    // Create Future task of type CustomerDetail
    FutureTask<CustomerDetail> customerDetailTask = new FutureTask<CustomerDetail>(
        @SuppressWarnings({ "unchecked", "rawtypes" })
        new Callable() {
            @Override
            public CustomerDetail call() throws Exception {
                return customerDetailService.getCustomerDetail(customerId);
            }
        }
    );


    // Create Future task of type PaymentResponse           
    FutureTask<PaymentResponse> paymentProcessingTask = new FutureTask<PaymentResponse>(
        @SuppressWarnings({ "unchecked", "rawtypes" })
        new Callable() {
            @Override
            public PaymentResponse call() throws Exception {
                return paymentProcessingService.processPayment(paymentRequest);
            }
        }
    );

    // Call two tasks asynchronously
    callAsynchronously(customerDetailTask, paymentProcessingTask);

catch (Exception e) {
    log.error(e);
}


private PaymentResponse callAsynchronously(FutureTask<CustomerDetail> customerDetailTask, FutureTask<PaymentResponse> paymentTask) throws InterruptedException, ExecutionException {
    ExecutorService executor = Executors.newFixedThreadPool(2);
    if (customerDetailTask != null) {
        executor.execute(customerDetailTask);
    }
    executor.execute(paymentTask);

    while (true) {
        if (paymentTask.isDone()) {
            log.info("Payment task done.");
            PaymentResponse payResponse = paymentTask.get();
            if (customerDetailTask != null ) {
                if ( customerDetailTask.isDone() ) {
                    log.info("Customer detail task done.");
                    payResponse.setCustomerDetail(customerDetailTask.get());
                    return payResponse;
                }
            } else {
                log.info("Payment without Customer detail task.");
                return payResponse;
            }
        }
    }
}

You may take a look at various frameworks for creating concurrent networks services. First of all servlets since 3.0 have asynchronous API ( http://www.javaworld.com/article/2077995/java-concurrency/asynchronous-processing-support-in-servlet-3-0.html ). The second option is to use a more specialized framework like for example Akka

Count Down Latch

A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.

Sample usage:

Here is a pair of classes in which a group of worker threads use two countdown latches:

  • The first is a start signal that prevents any worker from proceeding until the driver is ready for them to proceed;
  • The second is a completion signal that allows the driver to wait until all workers have completed.

Code:

class Driver { // ...
    void main() throws InterruptedException {
        CountDownLatch startSignal = new CountDownLatch(1);
        CountDownLatch doneSignal = new CountDownLatch(N);

        for (int i = 0; i < N; ++i)
            // create and start threads
            new Thread(new Worker(startSignal, doneSignal)).start();

        doSomethingElse(); // don't let run yet
        startSignal.countDown(); // let all threads proceed
        doSomethingElse();
        doneSignal.await(); // wait for all to finish
    }
}

class Worker implements Runnable {
    private final CountDownLatch startSignal;
    private final CountDownLatch doneSignal;

    Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
        this.startSignal = startSignal;
        this.doneSignal = doneSignal;
    }

    public void run() {
        try {
            startSignal.await();
            doWork();
            doneSignal.countDown();
        } catch (InterruptedException ex) {
        } // return;
    }

    void doWork() { ... }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top