在异步方法

时间:2018-01-25 11:03:01

标签: multithreading asynchronous java-ee error-handling

使用休息服务会触发长时间运行的进程。并行运行它是没有意义的,主服务被定义为具有默认并发管理策略的Singleton。在休息时,会立即发送响应,仅用于通知,它已被触发。要将主要服务中的方法归档为异步:

@Singleton
public class MainService {
    @Asynchronous
    public void mainTask(){ ... }

要在应用程序服务器中处理异步任务,可以创建许多线程的限制。在达不到这个限制之前一切正常。任务被触发并排队。

但是一旦达到限制,应用程序服务器就会抛出javax.ejb.ConcurrentAccessTimeoutException

在这种情况下,我捕获异常并尝试在响应中指定它已经被触发。

@Path(ServiceRest.URL)
public class ServiceRest {
    @Inject
    MainService mainService;
    @GET
    public String trigger(){
        try {
            mainService.mainTask();
            return "Triggered";
        } catch (javax.ejb.ConcurrentAccessTimeoutException e){
            String message = "Already in progress.";
            logger.error(message);
            return message;
        }
    }

问题是,我从未捕获过此异常。我总是收到回复的消息:"触发"。但在日志中,我可以看到在某些情况下:

11:42:00,308 ERROR [org.jboss.as.ejb3.invocation] (EJB default - 4) JBAS014134: EJB Invocation failed on component MainService for method public void MainService.mainTask(): javax.ejb.ConcurrentAccessTimeoutException: JBAS014373: EJB 3.1 PFD2 4.8.5.5.1 concurrent access timeout on org.jboss.invocation.InterceptorContext$Invocation@7be454f8 - could not obtain lock within 5000MILLISECONDS
    at org.jboss.as.ejb3.concurrency.ContainerManagedConcurrencyInterceptor.processInvocation(ContainerManagedConcurrencyInterceptor.java:100) [wildfly-ejb3-8.2.0.Final.jar:8.2.0.Final]
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.invocation.InterceptorContext$Invocation.proceed(InterceptorContext.java:407)
    at org.jboss.weld.ejb.AbstractEJBRequestScopeActivationInterceptor.aroundInvoke(AbstractEJBRequestScopeActivationInterceptor.java:55) [weld-core-impl-2.2.6.Final.jar:2014-10-03 10:05]
    at org.jboss.as.weld.ejb.EjbRequestScopeActivationInterceptor.processInvocation(EjbRequestScopeActivationInterceptor.java:83) [wildfly-weld-8.2.0.Final.jar:8.2.0.Final]
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.as.ee.concurrent.ConcurrentContextInterceptor.processInvocation(ConcurrentContextInterceptor.java:45) [wildfly-ee-8.2.0.Final.jar:8.2.0.Final]
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.invocation.InitialInterceptor.processInvocation(InitialInterceptor.java:21)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:61)
    at org.jboss.as.ee.component.interceptors.ComponentDispatcherInterceptor.processInvocation(ComponentDispatcherInterceptor.java:53)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.as.ejb3.component.singleton.SingletonComponentInstanceAssociationInterceptor.processInvocation(SingletonComponentInstanceAssociationInterceptor.java:52) [wildfly-ejb3-8.2.0.Final.jar:8.2.0.Final]
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.as.ejb3.tx.CMTTxInterceptor.invokeInOurTx(CMTTxInterceptor.java:273) [wildfly-ejb3-8.2.0.Final.jar:8.2.0.Final]
    at org.jboss.as.ejb3.tx.CMTTxInterceptor.required(CMTTxInterceptor.java:340) [wildfly-ejb3-8.2.0.Final.jar:8.2.0.Final]
    at org.jboss.as.ejb3.tx.CMTTxInterceptor.processInvocation(CMTTxInterceptor.java:239) [wildfly-ejb3-8.2.0.Final.jar:8.2.0.Final]
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.as.ejb3.component.interceptors.CurrentInvocationContextInterceptor.processInvocation(CurrentInvocationContextInterceptor.java:41) [wildfly-ejb3-8.2.0.Final.jar:8.2.0.Final]
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.as.ejb3.component.invocationmetrics.WaitTimeInterceptor.processInvocation(WaitTimeInterceptor.java:43) [wildfly-ejb3-8.2.0.Final.jar:8.2.0.Final]
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.as.ejb3.security.SecurityContextInterceptor.processInvocation(SecurityContextInterceptor.java:95) [wildfly-ejb3-8.2.0.Final.jar:8.2.0.Final]
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.as.ejb3.component.interceptors.ShutDownInterceptorFactory$1.processInvocation(ShutDownInterceptorFactory.java:64) [wildfly-ejb3-8.2.0.Final.jar:8.2.0.Final]
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.as.ejb3.component.interceptors.LoggingInterceptor.processInvocation(LoggingInterceptor.java:59) [wildfly-ejb3-8.2.0.Final.jar:8.2.0.Final]
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.as.ee.component.NamespaceContextInterceptor.processInvocation(NamespaceContextInterceptor.java:50)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.as.ejb3.component.interceptors.AdditionalSetupInterceptor.processInvocation(AdditionalSetupInterceptor.java:55) [wildfly-ejb3-8.2.0.Final.jar:8.2.0.Final]
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.invocation.ContextClassLoaderInterceptor.processInvocation(ContextClassLoaderInterceptor.java:64)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.invocation.InterceptorContext.run(InterceptorContext.java:326)
    at org.wildfly.security.manager.WildFlySecurityManager.doChecked(WildFlySecurityManager.java:439)
    at org.jboss.invocation.AccessCheckingInterceptor.processInvocation(AccessCheckingInterceptor.java:61)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.invocation.InterceptorContext.run(InterceptorContext.java:326)
    at org.jboss.invocation.PrivilegedWithCombinerInterceptor.processInvocation(PrivilegedWithCombinerInterceptor.java:80)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:61)
    at org.jboss.as.ee.component.ViewService$View.invoke(ViewService.java:185)
    at org.jboss.as.ee.component.ViewDescription$1.processInvocation(ViewDescription.java:182)
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.as.ejb3.component.interceptors.LogDiagnosticContextRecoveryInterceptor.processInvocation(LogDiagnosticContextRecoveryInterceptor.java:79) [wildfly-ejb3-8.2.0.Final.jar:8.2.0.Final]
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
    at org.jboss.as.ejb3.component.interceptors.AsyncFutureInterceptorFactory$1$2.runInvocation(AsyncFutureInterceptorFactory.java:97) [wildfly-ejb3-8.2.0.Final.jar:8.2.0.Final]
    at org.jboss.as.ejb3.component.interceptors.AsyncInvocationTask.run(AsyncInvocationTask.java:73) [wildfly-ejb3-8.2.0.Final.jar:8.2.0.Final]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [rt.jar:1.8.0_151]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [rt.jar:1.8.0_151]
    at java.lang.Thread.run(Thread.java:748) [rt.jar:1.8.0_151]
    at org.jboss.threads.JBossThread.run(JBossThread.java:122)

根据日志,应用程序服务器在内部调用mainTask()方法。 trigger()已经完成并返回了响应。如果没有空闲的线程/线程无法创建来处理任务,我在日志中得到异常,这是我无法捕获的。

我能以某种方式找到解决方法吗?我想避免在日志中出现这样的错误,因为在我的情况下它不是一个错误?我有一个解决方案,但首先想听听其他一些意见。

1 个答案:

答案 0 :(得分:0)

当调用异步方法时,它会在另一个由应用程序服务器管理的线程中调用,我无法捕获异常。 (如果我错了,请纠正我)

我不得不重新设计我的主要服务。

  1. 首先,仍然应该创建一个实例,所以它是 单身。
  2. 我保持状态,当它被触发时。
  3. 主要逻辑在异步方法中运行,该方法仅在确切时间调用一次。它甚至没有排队。
  4. 因为现在涉及2个方法,我不能使用默认的并发管理策略,所以我默认应用了@Lock(LockType.READ)注释。
  5. 要运行异步方法,必须通过save() { if (this.newSubProjectName.length > 0) { this.working = true; const newSubProject: SubProject = emptySubProject(); newSubProject.name = this.newSubProjectName; newSubProject.id = Math.random().toString(); newSubProject.color = this.newSubProjectColor; newSubProject.positionIds = this.positionIds; this.project.subProjectIds.push(newSubProject.id); // Here is the id of subproject when it is pushed into interface of project this.store.dispatch(new UpsertSubProjectInternalAction(newSubProject)); this.store.dispatch(new UpsertProjectInternalAction(this.project)); this.newSubProjectName = ''; } } 自代理运行。
  6. 这是一项休息服务:

    that

    主要服务:

    @Path(ServiceRest.URL)
    public class ServiceRest {
        @Inject
        MainService mainService;
        @GET
        public String trigger(){
            mainService.mainTask();
            return "Triggered";
        }
    

    可能有一个更好,更简单的解决方案,请告诉我。