Waiting at most X seconds for Async EJBs

2019-08-29 09:23发布

问题:

I have a "client" EJB that invokes 4 Asynchronous EJBs and should give them all 5 seconds to run. After 5 seconds the "client" EJB collects the ready results from Future object that finished running, and returns output.

I have a problem with the "waiting" in client part. I tried to invoke future.get(5, TimeUnit.MILLISECONDS) It seems like sometimes async EJBs start to run after the timeout. Is there a correct way to do it?

1) Collect Future objects in Map:

    Map<String, Future> futureMap = new HashMap<String, Future>();
    for (String userID: users) {
            Future<Set<FrontPageData>> test = util.asyncGetData(userID);
            futureMap.put(serviceID, test);

    }
    return futureMap;

2) Then I get output with timeout from Future objects

    final long now = Calendar.getInstance().getTimeInMillis();
    final long end = now + TimeUnit.SECONDS.toMillis(5)
    Map<String, Object> output = new HashMap<String, Object>();
    Object data;
    for (String userID: futureMap.keySet()) {
        Future future= futureMap.get(userID);
        try {
            //check how much time left till the end
            long timeout = end - Calendar.getInstance().getTimeInMillis();
            data = future.get(timeout, TimeUnit.MILLISECONDS);
            output.put(userID, data);
        } catch (Exception e) {//write to logs
        } 
    }
    return output;
}

thank you

回答1:

I don't think your client should be aware of the details whether the async code still has to be scheduled or whether it has been running for those 5 seconds.

All your client should be concerned about is the total waiting time. Since no system has unlimited resources, there can't be any guarantee that the async code starts running right away.

If you want to limit the actual execution time to 5 seconds, the only realistic way is to do this in the bean that executes the code.

p.s.

Not related to your question, but why do this weird calculation for timeout? You now do "now + 5 seconds - now", which is 5 seconds again.

And, if you iterate over a Map and need both the value and key, you can iterate over the entrySet, instead of over the key set and then doing a get() for each key.