Thread.sleep() в EJB
Я знаю, что беспорядок в потоках внутри EJB - это большой нет-нет, но я хотел бы попросить совета относительно того, как обрабатывать этот случай. Мой EJB вызывает внешний веб-сервис, который иногда может возвращать статус "занят". Когда это произойдет, я хотел бы подождать некоторое время, а затем повторно отправить запрос, используя те же данные, что и раньше.
Каким будет лучший способ реализовать это?
Ответы
Ответ 1
В часто задаваемые вопросы по ограничениям EJB в нем указано, что вы
не следует создавать или управлять потоками
И включение потока в сон считается "управлением".
В вашем случае, когда веб-служба возвращает статус "занят", вы можете запланировать задание, чтобы повторить отправку сообщения в более поздний момент времени, например, используя Quartz Scheduler. Выполнение завершится там, и любая дальнейшая обработка должна быть делегирована планировщику заданий.
Ответ 2
EJB 3.1 принес новый @Asynchronous
feature, который вы можете использовать:
@Asynchronous
@TransactionAttribute(NOT_SUPPORTED)
public Future<WebServiceResult> callWebService(int retries) {
WebServiceResult result = webService.call();
if (!result.equals(BUSY)) {
return result;
}
if (retries <= 0) {
throw new TooBusyException();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return callWebService(retries - 1);
}
Затем просто позвоните в веб-службу:
Future<WebServiceResult> result = yourEJB.callWebService(1);
// Can do some interesting stuff here.
// ...
// ...
result.get(2, SECONDS); // Block for up to 2 seconds.
Как вы можете видеть, вы получаете настраиваемое количество попыток и тайм-аута бесплатно.
Как это отличается от простого вызова Thread.sleep()
? Возврат Future
более явный и управляемый. Также я не думаю, что Thread.sleep()
- это вредно. Единственная проблема заключается в том, что этот экземпляр EJB теперь может использоваться повторно другими клиентами. При асинхронном вызове Future
происходит внутри некоторого другого EJB и пула потоков. Что касается важности Thread#interrupt()
внутри блока catch, обратитесь к Зачем вызывать Thread.currentThread.interrupt(), когда вы catch any InterruptException?
Другая идея: использовать аспект во время вызова веб-сервиса, ловить BusyException
один раз и повторить попытку.
Ответ 3
Но внешний веб-сервис является внешним, и вы открываете ему сетевое соединение, и вы хотите сделать некоторые вещи управления. Для JCA это не EJB.