简体   繁体   English

在不使用线程的情况下处理 EJB3 中的超时

[英]Handling a timeout in EJB3 without using threads

I have the following situation.我有以下情况。 I have a job that:我有一份工作:

  • May time out after a given amount of time, and if so occurs needs to throw an exception可能在给定时间后超时,如果发生需要抛出异常
  • If it does not time out, will return a result如果没有超时,将返回一个结果
  • If this job returns a result, it must be returned as quickly as possible, because performance is very much an issue.如果此作业返回结果,则必须尽快返回,因为性能是一个非常重要的问题。 Asynchronous solutions are hence off the table, and naturally tying up the system by hammering isn't an option either.因此,异步解决方案不再适用,自然地通过锤击来捆绑系统也不是一种选择。
  • Lastly, the system has to conform to the EJB standard, so AFAIK using ordinary threads is not an option, as this is strictly forbidden.最后,系统必须符合 EJB 标准,因此不能选择使用普通线程的 AFAIK,因为这是严格禁止的。

Our current solution uses a thread that will throw an exception after having existed for a certain amount of time without being interrupted by an external process, but as this clearly breaks the EJB standard, we're trying to solve it with some other means.我们当前的解决方案使用一个线程,该线程会在存在一定时间后抛出异常而不会被外部进程中断,但是由于这显然违反了 EJB 标准,我们正在尝试通过其他方式解决它。

Any ideas?有任何想法吗?

Edited to add: Naturally, a job which has timed out needs to be removed (or interrupted) as well.编辑添加:自然,超时的作业也需要删除(或中断)。

Edited to add 2: This issue doesn't seem to have any solution, because detecting a deadlock seems to be mostly impossible sticking to pure EJB3 standards.编辑添加2:这个问题似乎没有任何解决方案,因为检测死锁似乎几乎不可能坚持纯EJB3标准。 Since Enno Shioji's comments below reflect this, I'm setting his suggestion as the correct answer.由于 Enno Shioji 下面的评论反映了这一点,我将他的建议设置为正确答案。

With Bean Managed Transaction, the timeout for the specific transaction can be specified by using UserTransaction interface.使用 Bean Managed Transaction,可以使用 UserTransaction 接口指定特定事务的超时时间。

Modify the timeout value that is associated with transactions started by the current thread with the begin method.使用 begin 方法修改与当前线程启动的事务关联的超时值。

void setTransactionTimeout(int seconds) throws SystemException
  • Transaction will timeout after specified seconds & may not get propagated further.事务将在指定秒后超时,并且可能不会进一步传播。 If exception is not thrown implicitly, then can throw it explicitly based on the result.如果异常没有隐式抛出,则可以根据结果显式抛出。
  • Will return a result on successful completion within specified time.将在指定时间内成功完成返回结果。
  • Can use it with stateless session beans so there may not be a performance issue.可以将它与无状态 session bean 一起使用,因此可能不会出现性能问题。
  • Its EJB standard so that will not be an issue to implement.它的 EJB 标准因此不会成为实施的问题。

With little-bit work around, it should work fine in the given scenario.通过一点点工作,它应该在给定的场景中工作正常。

Edit: Also can use server specific properties to manage transaction timeout.编辑:也可以使用服务器特定的属性来管理事务超时。

JBoss : At either at class or method level annotation @TransactionTimeout(100) can be applied. JBoss :可以在 class 或方法级别注释@TransactionTimeout(100)应用。

Weblogic : Specifying the parameters in weblogic-ejb-jar.xml Weblogic :在 weblogic-ejb-jar.xml 中指定参数

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

GlassFish : Using the optional cmt-timeout-in-seconds element in sun-ejb-jar.xml GlassFish :在 sun-ejb-jar.xml 中使用可选的cmt-timeout-in-seconds元素

This is more like a request for clarification, but it's too long to fit as a comment..这更像是一个澄清请求,但它太长了,不适合作为评论..

I'm not sure how you are doing it right now, since from what you wrote, just using the request processing thread seems to be the way to go.我不确定你现在是怎么做的,因为从你写的内容来看,仅仅使用请求处理线程似乎是 go 的方式。 Like this:像这样:

//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");
    }
}

I'm not sure why you are creating threads at all.我不确定你为什么要创建线程。 If you are forced to use threads because the getResult method doesn't timeout at all, you would have a thread leak.如果您因为getResult方法根本没有超时而被迫使用线程,那么您将遇到线程泄漏。 If it timeouts after a longer time and thus you want to "shortcut" your reply to the user, that would be the only case I'd consider using a thread like I imagine how you are using it.如果它在较长时间后超时,因此您想“快捷地”回复用户,那将是我考虑使用线程的唯一情况,就像我想象的那样使用它。 This could result in Threads piling up under load and I'd strive to avoid such situation.这可能会导致线程在负载下堆积,我会努力避免这种情况。

Maybe you can post some code and let us know why you are creating in your service at all?也许您可以发布一些代码,让我们知道您为什么要在服务中创建?

Also, what's your client interface?另外,您的客户端界面是什么? Sounds like it's a synchronous webservice or something?听起来像是一个同步网络服务之类的?


In that case, if I were you I would use a HashedWheelTimer as a singleton... this mechanism should work great with your requirement ( here is an implementation ). 在这种情况下,如果我是你,我会使用HashedWheelTimer作为 singleton ......这个机制应该很好地满足你的要求( 这里是一个实现)。 However, this unfortunately seem to conflict with the ban on threading AND the ban on singleton in the EJB spec. 然而,不幸的是,这似乎与 EJB 规范中对线程的禁令和对 singleton 的禁令相冲突。 In reality though there really isn't a problem if you would do this. 实际上,如果您这样做,确实没有问题。 See this discussion for example. 例如,请参阅此讨论 We have also used the singleton pattern in our EJB app. 我们还在 EJB 应用程序中使用了 singleton 模式。 which used JBoss. 它使用了 JBoss。 However, if this isn't a viable choice then I might look at isolating the processing in its own JVM by defining a new web service (and deploy it in a web-container or something), and call that service from the EJB app. 但是,如果这不是一个可行的选择,那么我可能会考虑通过定义新的 web 服务(并将其部署在 Web 容器或其他东西中)来隔离其自己的 JVM 中的处理,并从 EJB 应用程序调用该服务。 This would however obviously incur performance hit and now you would have another whole new app. 然而,这显然会导致性能下降,现在您将拥有另一个全新的应用程序。

Stick the process and it's timeout thread in to a class annotated with @WebService, put that class in to a WAR, then invoke the WebService from your EJB.将进程及其超时线程插入带有@WebService 注释的 class 中,然后从 EJB 调用 WebService。

WARs don't have the same limitations or live under the same contract that EJBs do, so they can safely run threads. WAR 没有 EJB 那样的限制或遵循相同的契约,因此它们可以安全地运行线程。

Yes, I consider this a "hack", but it meets the letter of the requirements, and it's portable.是的,我认为这是一种“hack”,但它符合要求,并且是可移植的。

You can create threads using the commonj WorkManager.您可以使用 commonj WorkManager 创建线程。 There are implementations built into WebSphere and Weblogic as they proposed the standard, but you can also find implementations for other appservers as well. WebSphereWeblogic在提出标准时内置了一些实现,但您也可以找到其他应用服务器的实现。

Basically, the WorkManager allows you to create managed threads inside the container, much like using an Executor in regular Java.基本上,WorkManager 允许您在容器内创建托管线程,就像在常规 Java 中使用 Executor 一样。 Your only other alternative would be to use MDB's, but that would be a 'heavier' solution.您唯一的其他选择是使用 MDB,但这将是一个“更重”的解决方案。

Since I don't know your actual platform, you will have to google commonj with your platform yourself 8-)由于我不知道你的实际平台,你必须自己用你的平台谷歌 commonj 8-)

Here is a non IBM or Oracle solution.这是一个非 IBM 或 Oracle 解决方案。

Note: This is not an actual standard, but it is widely available for different platforms and should suit your purposes nicely.注意:这不是一个实际的标准,但它可以广泛用于不同的平台,并且应该很好地适合您的目的。

For EJBs, there is a concept of "Container Managed Transactions".对于 EJB,有一个“容器管理事务”的概念。 By specifying @TransactionAttribute on your bean, or specific method, the container will create a transaction when ever the method(s) are invoked.通过在 bean 或特定方法上指定 @TransactionAttribute,容器将在调用方法时创建事务。 If the execution of the code takes longer than the transaction threshold, the container will throw an exception.如果代码的执行时间超过事务阈值,容器会抛出异常。 If the call finishes under the transaction threshold, it will return as usual.如果调用在事务阈值以下完成,它将照常返回。 You can catch the exception in your calling code and handle it appropriately.您可以在调用代码中捕获异常并适当地处理它。

For more on container managed transactions, check out: http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/Transaction3.html and http://download.oracle.com/javaee/5/tutorial/doc/bncij.html For more on container managed transactions, check out: http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/Transaction3.html and http://download.oracle.com/javaee/5/tutorial/ doc/bncij.html

You could use @TimeOut .您可以使用@TimeOut Something like:就像是:

@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);
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM