Search code examples
jakarta-eeasynchronousejbapache-tomee

@Asynchronous method in Tomee generates memory leak log error


I have a @Asynchronous method in a singleton class which gets called from a EJB to do some cleanup in the system.

@Singleton
public class AuthTokenCleanup {

    @Inject
    AuthTokenService tokenService;

    @Asynchronous
    @Lock(LockType.READ)
    @TransactionAttribute(NOT_SUPPORTED)
    public void scheduleCleanupAuthTokens() {

        try {
            Thread.sleep(5000);
            tokenService.cleanup();
        } catch (InterruptedException ex) {
        }
    }
}

The snippet of code that is calling the singleton. It is inside a @Stateless EJB

public boolean authenticate(String username, String password) {

      boolean authenticated = false;

      try{  
        Login login = loginLookup.findByUsername(username);
        authenticated = login.equalPassword(password);
      } finally {
        tokenCleanup.scheduleCleanupAuthTokens(); //token cleanup happens here
      }

      return authenticated;
}

When undeploying the application it takes about 20-30 seconds. I see the following error in the catalina log file

SEVERE: The web application [/MyApp] 
appears to have started a thread named [@Asynchronous MyApp-1.0-SNAPSHOT - 3] 
but has failed to stop it. This is very likely to create a memory leak.

I'm running the application on Apache-tomee-1.7.1-jaxrs. A snippet of my pom.xml config

    <properties>
        <tomee.version>1.7.1</tomee.version>
        <openejb.javaee.api>6.0-6</openejb.javaee.api>        
        <endorsed.dir>${project.build.directory}/endorsed</endorsed.dir>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.2</version>
        <configuration>
          <source>1.7</source>
          <target>1.7</target>
          <compilerArguments>
               <endorseddirs>${endorsed.dir}</endorseddirs>
          </compilerArguments>
        </configuration>
    </plugin>

When I remove the @Asynchronous call the undeploy takes 1-3 seconds and no error in log file.

Is the behavior and error expected in TomEE when using a @Asynchronous method call if not what am I doing wrong?


Solution

  • The EJB spec requires that EJB components do not directly access thread primitives (including Thread.sleep()). This is because the container needs to handle thread management, and won't be able to do this efficiently if the application is doing this.

    If the clean-up task needs to be done regularly in a singleton, have you considered using a scheduled job, using the @Schedule annotation? This will fit better with the EJB model, and also means that you're not starting a new asynchronous request for every call processed, so it's likely to scale much better too.