Wildfly Threads - Multiple instances of @Singleton

Címkék
Wildfly Threads - Multiple instances of @Singleton
2022-09-13T12:03:41+02:00
2022-09-14T09:11:08+02:00
2022-09-14T09:41:56+02:00
Axxtros
Sziasztok,

Van egy JEE alkalmazás, ami Wildfly alatt fut, és a probléma az, hogy ha implementálok egy @Startup @Singleton bean-t, @ConcurrencyManagement(CONTAINER) annotációval megjelölve, két külön szálon jön létre az adott bean egy-egy példánya. Utánaolvastam, mások is belefutottak ebbe a probléma, de egzakt megoldást, nem találtam rá. Alapvetően nem lenne probléma, de most úgy alakult, hogy egy timerService-t kell(ene) benne majd indítani, ami eléggé adatbázis igényes műveletet futtatna le, éjjel, naponta egyszer, és az nem megengedhető, hogy ez az egész két szálban, gyakorlatilag párhuzamosan fusson. Meg amúgy is, Singleton bean-től azt várja az ember, hogy egy példányban legyen jelen a memóriában, egy JVM-en (ClassLoader-en) belül.
Én azt gondolom, hogy itt nem is lehet ennél szofisztikáltabban megadni kódszinten ennek az osztálynak a leírását, hanem Wildfly szinten kell(ene) ezt "valahogy" helyesen konfigurálni.
Tehát nem kell messzire menni, egy sima demo class esetén is két külön szálban írja konzolra a log üzenetet, ami a PostConstructor-ban van definiálva.
Érdekes módon eddig ilyet sem Payara-ban, sem pedig Weblogic-ban nem tapasztaltam. Hátha valaki már találkozott ezzel, és van rá valami ötlete.

@Startup @Singleton @ConcurrencyManagement(value = ConcurrencyManagementType.CONTAINER) @DependsOn("ApplicationEJB") public class DemoTimer implements Serializable { @PostConstruct private void init() { LOG.info("DemoTimer init..."); } }
Log:

11:56:22,583 INFO [stdout] (ServerService Thread Pool -- 185) 2022.09.13 11:56:22,582 [ServerService Thread Pool -- 185] [INFO ] DemoTimer - DemoTimer init... 11:56:22,632 INFO [stdout] (ServerService Thread Pool -- 211) 2022.09.13 11:56:22,631 [ServerService Thread Pool -- 211] [INFO ] DemoTimer - DemoTimer init...
Tehát a fenti példán látható, hogy a 185 és a 211 id-val megjelölt thread is létrejött, nagyon kicsi idő deltával, de innentől mindkettő fut a háttérben - ha erre még komplex implementáció is rá lenne kötve, akkor természetesen azok is lefutnának.
Mutasd a teljes hozzászólást!
Meglett a probléma forrása. A war és az ejb project maven dependency összerendelésében volt a probléma. A war project-be függőségként van injectálva az ejb project, de mivel nem volt explicit megadva a war pom.xml-ben, hogy ennek a scope-ja provided legyen, így a war csomagba bekerült az ejb project teljes másolata, és ez miatt gyakorlatilag egy dupla ejb-t tartalmazott a komplett ear.
Ez egyébként önmagában is problémás, nem csak a mostani timer miatt, hanem az egész project globális műkődése szempontjából. Tehát erre figyelni kell, hogy közvetlen ejb projectet mindig provided scope-al adjunk hozzá a war-hoz.
Így viszont most már a @Startup @Singleton bean valóban csak egy példányban jön létre - egy szálon - és a timer is csak egyszer futtatja le a szükséges implementációkat.

Amit @H.Lilla javasolt, jó ötlet, csak mivel itt egy csomagról (ear) volt szó, így a getClass().getClassLoader() nem adta meg pontosan, hogy a két példány honnan jön létre, mert azonos volt a class loader. De az ötlet jó volt.

Végül ez a link adta meg a segítséget. Igaz, itt scheduler-ről van szó, de a probléma lényegére választ adott.

Tehát a war pom.xml-jében az ejb-re való hivatkozásnak valami ilyesminek kell lennie:

<dependencies> <dependency> <groupId>${project.groupId}</groupId> <artifactId>ejb-project</artifactId> <version>1.0</version> <type>jar</type> <scope>provided</scope> </dependency> </dependencies>
Mutasd a teljes hozzászólást!

  • Szia!

    Ötletem nincs, de pont most szaladtam bele Weblogic, pontosabban JDeveloper 12.2 esetén hasonlóba.

    Ha JDeveloperben az alkalmazást a "Deploy" paranccsal rárakom az IntegratedWeblogicServer-re, akkor minden rendben, a Singletonokból egy példány jön létre (tehát maga a WebLogic elvileg rendben van). Viszont ha csak "simán", pl. "Run", "Debug" vagy más gyors tesztelő eljárással indítom (és ezért magától deployol, valamilyen más módon), akkor ugyanaz a jelenség, mint a te esetedben.
    Mutasd a teljes hozzászólást!
  • A konstruktorban lenne érdemes megnézni a getClass-t és egy stack trace-t, hogy honnan jön a második példányosítás. (A tippem: Nem lehet, hogy a runtime egy proxyval származik le az osztályodból, mert nem interfészen keresztül van regisztrálva a DI containerbe?)
    Mutasd a teljes hozzászólást!
  • Meglett a probléma forrása. A war és az ejb project maven dependency összerendelésében volt a probléma. A war project-be függőségként van injectálva az ejb project, de mivel nem volt explicit megadva a war pom.xml-ben, hogy ennek a scope-ja provided legyen, így a war csomagba bekerült az ejb project teljes másolata, és ez miatt gyakorlatilag egy dupla ejb-t tartalmazott a komplett ear.
    Ez egyébként önmagában is problémás, nem csak a mostani timer miatt, hanem az egész project globális műkődése szempontjából. Tehát erre figyelni kell, hogy közvetlen ejb projectet mindig provided scope-al adjunk hozzá a war-hoz.
    Így viszont most már a @Startup @Singleton bean valóban csak egy példányban jön létre - egy szálon - és a timer is csak egyszer futtatja le a szükséges implementációkat.

    Amit @H.Lilla javasolt, jó ötlet, csak mivel itt egy csomagról (ear) volt szó, így a getClass().getClassLoader() nem adta meg pontosan, hogy a két példány honnan jön létre, mert azonos volt a class loader. De az ötlet jó volt.

    Végül ez a link adta meg a segítséget. Igaz, itt scheduler-ről van szó, de a probléma lényegére választ adott.

    Tehát a war pom.xml-jében az ejb-re való hivatkozásnak valami ilyesminek kell lennie:

    <dependencies> <dependency> <groupId>${project.groupId}</groupId> <artifactId>ejb-project</artifactId> <version>1.0</version> <type>jar</type> <scope>provided</scope> </dependency> </dependencies>
    Mutasd a teljes hozzászólást!
Címkék
Tetszett amit olvastál? Szeretnél a jövőben is értesülni a hasonló érdekességekről?
abcd