Обработка таймаута в EJB3 без использования потоков - PullRequest
4 голосов
/ 26 мая 2011

У меня следующая ситуация.У меня есть задание, которое:

  • Может истечь по истечении заданного промежутка времени, и, если это произойдет, необходимо сгенерировать исключение
  • Если оно не истекло, вернетрезультат
  • Если это задание возвращает результат, он должен быть возвращен как можно быстрее, так как производительность очень важна.Асинхронные решения, следовательно, не обсуждаются, и естественная привязка системы с помощью молотка также невозможна.
  • Наконец, система должна соответствовать стандарту EJB, поэтому использование AFAIK с использованием обычных потоков не является опцией, так как это строго запрещено.

Наше текущее решение использует поток, который будет генерировать исключение после того, как он существовал в течение определенного периода времени без прерывания внешним процессом, но поскольку это явно нарушает стандарт EJB, мы пытаемсячтобы решить его другими способами.

Есть идеи?

Отредактировано, чтобы добавить: Естественно, задание, которое истекло по тайм-ауту, должно быть удалено (или прервано) какхорошо.

Отредактировано, чтобы добавить 2: Эта проблема, похоже, не имеет никакого решения, потому что обнаружение тупика кажется почти невозможным, если придерживаться чистых стандартов EJB3.Поскольку приведенные ниже комментарии Энно Сиоджи отражают это, я задаю его предложение как правильный ответ.

Ответы [ 6 ]

1 голос
/ 28 мая 2011

Прикрепите процесс и поток его ожидания к классу, аннотированному @WebService, поместите этот класс в WAR, а затем вызовите WebService из вашего EJB.

WAR не имеют тех же ограничений или действуют по тому же контракту, что и EJB, поэтому они могут безопасно запускать потоки.

Да, я считаю это "взломом", но он соответствует букве требований и переносим.

1 голос
/ 27 мая 2011

Это больше похоже на запрос о разъяснении, но оно слишком длинное, чтобы уместиться в качестве комментария ..

Я не уверен, как вы делаете это прямо сейчас, так как из того, что вы написали, просто используяпоток обработки запросов, кажется, путь.Вот так:

//Some webservice method (synchronous)
public Result process(Blah blah){
    try{
        return getResult(TimeUnit.SECONDS, 10);
    }catch(InterruptedException e){
        //No result within 10 seconds!
        throw new ServiceUnavailableException("blah");
    }
}

Я не уверен, зачем вы вообще создаете темы.Если вы вынуждены использовать потоки, потому что метод getResult вообще не имеет времени ожидания, у вас будет утечка потоков.Если он истекает через более длительное время и, таким образом, вы хотите «сократить» свой ответ пользователю, это будет единственный случай, когда я рассмотрю использование потока, как я представляю, как вы его используете.Это может привести к накоплению потоков под нагрузкой, и я постараюсь избежать такой ситуации.

Может быть, вы можете опубликовать некоторый код и сообщить нам, почему вы вообще создаете в своем сервисе?

Кроме того, каков ваш клиентский интерфейс?Похоже, это синхронный веб-сервис или что-то в этом роде?

В этом случае на вашем месте я бы использовал HashedWheelTimer в качестве одиночного ... этот механизм должен прекрасно работать с вашим требованием ( здесь есть реализация ).Однако, к сожалению, это противоречит запрету на многопоточность и запрету на синглтон в спецификации EJB.В действительности, хотя на самом деле нет проблем, если бы вы сделали это.См. это обсуждение например.Мы также использовали шаблон синглтона в нашем приложении EJB.который использовал JBoss.Однако, если это не жизнеспособный выбор, я мог бы взглянуть на изоляцию обработки в ее собственной JVM, определив новый веб-сервис (и развернув его в веб-контейнере или чем-то подобном), и вызвать этот сервис из приложения EJB.Однако это, очевидно, повлечет за собой снижение производительности, и теперь у вас будет еще одно совершенно новое приложение.

1 голос
/ 27 мая 2011

В управляемой компонентом транзакции тайм-аут для конкретной транзакции можно указать с помощью интерфейса UserTransaction.

Изменить значение времени ожидания, которое связанные с начатыми транзакциями по текущей теме с начала способ.

void setTransactionTimeout(int seconds) throws SystemException
  • Время транзакции истекает через указанные секунды и может не распространяться дальше. Если исключение не генерируется неявным образом, то оно может быть сгенерировано явно в зависимости от результата.
  • Вернет результат при успешном завершении в течение указанного времени.
  • Может использоваться с сеансными компонентами без сохранения состояния, поэтому проблем с производительностью может не быть.
  • Это стандарт EJB, поэтому его реализация не будет проблемой.

При небольшом обходе все должно работать нормально в данном сценарии.

Редактировать: Также можно использовать определенные свойства сервера для управления тайм-аутом транзакции.

JBoss : На уровне класса или метода может применяться аннотация @TransactionTimeout(100).

Weblogic : указание параметров в файле weblogic-ejb-jar.xml

<transaction-descriptor>
     <trans-timeout-seconds>100</trans-timeout-seconds> 
</transaction-descriptor>

GlassFish : Использование дополнительного элемента cmt-timeout-in-seconds в sun-ejb-jar.xml

0 голосов
/ 27 мая 2011

Вы можете использовать @TimeOut.Что-то вроде:

@Stateless
public class TimedBean {

  @Resource
  private TimerService timerService;

  static private AtomicInteger counter = new AtomicInteger(0);
  static private Map<Integer, AtomicBoolean> canIRunStore = new ...;

  public void doSomething() {
    Integer myId = counter.getAndIncrement();
    AtomicBoolean canIRun = new AtomicBoolean(true);
    canIRunStore.put(myId, canIRun);

    timerService.createTimer(1000, 0, myId);

    while (canIRun.get() /* && some other condition */) {
      // do my work ... untill timeout ... 
    }
  }

  @Timeout
  @PermitAll
  public void timeout(Timer timer) {
    Integer expiredId = (Integer) timer.getInfo();
    AtomicBoolean canHeRun = canIRunStore.get(expiredId);
    canIRunStore.remove(expiredId);
    canHeRun.set(false);
  }
}
0 голосов
/ 27 мая 2011

Для EJB существует концепция «Управляемые контейнером транзакции». Указав @TransactionAttribute в вашем бине или конкретном методе, контейнер будет создавать транзакцию при каждом вызове метода (ов). Если выполнение кода занимает больше времени, чем порог транзакции, контейнер сгенерирует исключение. Если вызов завершается ниже порога транзакции, он возвращается как обычно. Вы можете перехватить исключение в своем коде вызова и обработать его соответствующим образом.

Для получения дополнительной информации о транзакциях, управляемых контейнером, проверьте: http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/Transaction3.html и http://download.oracle.com/javaee/5/tutorial/doc/bncij.html

0 голосов
/ 26 мая 2011

Вы можете создавать темы, используя commonj WorkManager.Существуют реализации, встроенные в WebSphere и Weblogic , как они предложили стандарт, но вы также можете найти реализации и для других серверов приложений.

По сути, WorkManager позволяет вамсоздавать управляемые потоки внутри контейнера, очень похоже на использование Executor в обычной Java.Ваша единственная альтернатива - использовать MDB, но это будет более «тяжелое» решение.

Поскольку я не знаю вашу настоящую платформу, вам придется самостоятельно использовать Google для своей платформы 8 -)

Вот решение не IBM или Oracle.

Примечание: Это не является действующим стандартом, но он широко доступен для различных платформ идолжен хорошо соответствовать вашим целям.

...