07 lutego 2011

Uruchomić zadanie co 5 sekund w EJB 3.1 ze @Schedule(second = "*/5", info="Every 5 seconds")?

Pomyślałby kto, że uruchomienie zadania w EJB 3.1 co 5 sekund wymaga jedynie stworzenia bezstanowego ziarna sesyjnego z metodą opatrzoną adnotacją @Schedule(second = "*/5", info="Every 5 seconds") i gotowe. Nic bardziej mylnego! Okazuje się, że domyślne wartości dla atrybutów @Schedule to zerowa sekunda, minuta i godzina, więc brak ich określenia sprawi, że kolejne uruchomienie będzie o północy następnego dnia. Można się nieźle przejechać podczas wdrożenia.

Więcej (kompletny projekt i kilka dodatkowych przemyśleń) w artykule Uruchomienie cyklicznego zadania w EJB 3.1 ze @Schedule.

p.s. Wciąż zastanawiam się nad moim rozdwojeniem językowym - polskojęzycznym (tutaj) i angielskojęzycznym (na http://blog.japila.pl). Głównym motywem był brak interakcji z czytelnikami, co potwierdziła statystyka na blog.japila.pl, gdzie przy 11 wpisach mam 22 komentarze. Inaczej niż tutaj i po cichutku liczę na choć szczątkowy odzew, np. co należałoby usprawnić w artykule, a szczególnie w sekcji dotyczącej testowania. Nie mam lepszego pomysłu na przetestowanie @Schedule niż to, co zaproponowałem w artykule. Dotknął ktoś tego problemu? Jakieś wskazówki na bardziej eleganckie rozwiązanie?

p.s.2. W kolejnych odcinkach dalej o usłudze budzika (ang. timer service) w EJB 3.1. Może jakieś podpowiedzi, np. z jakim kontenerem? Brak traktuję jako zachętę ku IBM WebSphere Application Server V8 lub Apache OpenEJB 3.2.

13 komentarzy:

  1. Ładnie, prawie jak w Springu. Tam @Scheduled(fixedDelay=5000) na POJO działa tak jak byś oczekiwał (czas jest w milisekundach).

    Unit-testowałbym kod który piszesz (dla Ciebie run()), nie implementację cudzych bibliotek (czy kontener EJB rozumie @Scheduled). W przypadku, gdyby konfiguracja jest podatna na błędy (np. z AOP'em miałem takie sytuacje gdy cicho mi ktoś go wyłączał, więc Scheduler może być dobrym przypadkiem), zrób jeden test integracyjny, ale automatyczny, a nie manualny (System.out.println).

    Z ciała run() wywołaj metodę jakiegoś interfejsu, którą przykryjesz mockiem (np. z Mockito), następnie odpal test i zweryfikuj po 16 sekundach, że została wywołana metoda 3 razy (verify(myMock, times(3).methodName());

    Oczywiście, lepiej żeby to były milisekundy i cały test kończył się poniżej sekundy. Najlepiej dużo poniżej. Jak długo uruchamia się osadzony kontener EJB 3.1?

    OdpowiedzUsuń
  2. 1. Do kompletu wypada wspomnieć, że @Scheduled(cron="*/5 * * * * MON-FRI") również działa świetnie w Springu.

    2. Będąc adwokatem diabła napomknę jednak, że aby ta adnotacja zadziałała, musisz jednak nieco XMLa napisać, a i tak czasem potkniesz się o wymienione przez Ciebie problemy (znam i ja ten ból).

    3. Niech mi ktoś wytłumaczy, dlaczego Spring nie implementuje jeszcze całej specyfikacji EJB 3.1 (podpierając się zewnętrznymi bibliotekami)? Przecież de facto jest nadzbiorem... Wiem, że nieco inna filozofia i podejście, ale przynajmniej skończyłaby się wojna między tymi stosami...

    OdpowiedzUsuń
  3. Ciekawa informacja, chociaz w nietrywialnych przypadkach i tak parametry tego typu jobow lepiej przeniesc poza kod zrodlowy np. do plikow konfiguracyjnych. Czy jest na to jakis wygodny sposob w EJB 3.1?

    Przy okazji zastanawiam sie, jaki jest sens tworzenia testu jednostkowego dla tego typu funkcjonalnosci w ramach wlasnej aplikacji. Co taki test moze wykryc?

    OdpowiedzUsuń
  4. Dziękuję wszystkim za komentarze - odpowiedzi się już piszą! Zainspirowanym niezmiernie.

    OdpowiedzUsuń
  5. @Tomek Nurkiewicz
    Ad2. Bogu dzięki dużo tego xml'a nie ma. Dla 3.0.x jedynie:


    (dla jednego wątku)
    Po doświadczeniach z quartzem w Springu 2.5.6 byłem mile zaskoczony.

    @panczacza
    No właśnie testują, czy masz dobrą konfigurację, czyli np. czy w springu znajduje się powyższe. W końcu w testach, poza designem, chodzi o zarządzanie ryzykiem. Lubię mieć pewność, że mechanizm (AOP, scheduler, etc.) działa. Kilka razy gdy przestał (bo mi ktoś np. pointcuty na aspektach pozmieniał, albo zrefaktorował paczki tak że pointcuty przestały wskazywać poprawnie) miałem przykrego zonka.

    Dołączam się do Twojego pytania: czy jest sposób wyciągnięcia tej konfiguracji poza źródeła w EJB 3.1?

    OdpowiedzUsuń
  6. Ten komentarz został usunięty przez autora.

    OdpowiedzUsuń
  7. Ech, nie mam szczęścia z dodawaniem xmla w komentarzach. Miało być:

    <task:annotation-driven scheduler="emailSendingScheduller"/>
    <task:scheduler id="emailSendingScheduller" pool-size="1"/>

    OdpowiedzUsuń
  8. Jacek,
    Super sprawa. Fajnie było by gdyby przykłady były dla WAS8 i Glasfish.
    Pozdrowienia

    OdpowiedzUsuń
  9. Może oprócz WAS-a wypróbowałbyś jeszcze ciepłego, dopiero co wydanego JBossa 6?

    OdpowiedzUsuń
  10. Pytanie tylko po co testowac cos co jest czescia specyfikacji JEE6 :) ?

    Chyba nie testujesz np. wsztykiwania zaleznosci, albo tego czy JSF przechodzi odpowiednio przez wszystkie fazy ;-) ?

    T

    OdpowiedzUsuń
  11. @szimano, tu właśnie wychodzi brak mojego doświadczenia w projektach, gdzie wykorzystywano testy. Podpowiedź Jakuba była w dziesiątkę - testuję metodę, nie sposób jej uruchomienia.

    Skorzystałem z testów jednostkowych, aby mieć jakikolwiek sposób na uruchomienie i sprawdzenie, czy się uruchomiło poprawnie. Nie miałem innego sposobu/pomysłu, jakby to zrobić.

    OdpowiedzUsuń
  12. nie rozdwajaj się, bier tylko po angielsku :-)

    OdpowiedzUsuń
  13. a moze GlassFish :) (wersja angielska mysle w zupelnosci wystarczy - ilosc odbiorcow zdecydowanie wieksza)

    OdpowiedzUsuń