java ejb 3.1 中的定时器服务 - 调度调用超时问题

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2691835/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 22:22:48  来源:igfitidea点击:

Timer Service in ejb 3.1 - schedule calling timeout issue

javaglassfishtimerschedule

提问by Greg

I have created simple example with @Singleton, @Schedule and @Timeout annotations to try if they would solve my problem.

我用@Singleton、@Schedule 和@Timeout 注释创建了简单的示例,以尝试它们是否能解决我的问题。

The scenario is this: EJB calls 'check' function every 5 secconds, and if certain conditions are met it will create single action timer that would invoke some long running process in asynchronous fashion. (it's sort of queue implementation type of thing). It then continues to check, but while the long running process is there it won't start another one.

场景是这样的:EJB 每 5 秒调用一次“检查”函数,如果满足某些条件,它将创建单个动作计时器,以异步方式调用一些长时间运行的进程。(这是某种队列实现类型的东西)。然后它继续检查,但是虽然长时间运行的进程在那里,但它不会启动另一个进程。

Below is the code I came up with, but this solution does not work, because it looks like asynchronous call I'm making is in fact blocking my @Schedule method.

下面是我想出的代码,但这个解决方案不起作用,因为看起来我正在进行的异步调用实际上阻塞了我的 @Schedule 方法。

@Singleton
@Startup
public class GenerationQueue {

    private Logger logger = Logger.getLogger(GenerationQueue.class.getName());

    private List<String> queue = new ArrayList<String>();

    private boolean available = true;

    @Resource
    TimerService timerService;

    @Schedule(persistent=true, minute="*", second="*/5", hour="*")
    public void checkQueueState() {

        logger.log(Level.INFO,"Queue state check: "+available+" size: "+queue.size()+", "+new Date());

        if (available) {

            timerService.createSingleActionTimer(new Date(), new TimerConfig(null, false));
        }

    }

    @Timeout
    private void generateReport(Timer timer) {

        logger.info("!!--timeout invoked here "+new Date());

        available = false;

        try {

            Thread.sleep(1000*60*2); // something that lasts for a bit

        } catch (Exception e) {}

        available = true;

        logger.info("New report generation complete");

    }

What am I missing here or should I try different aproach? Any ideas most welcome :)

我在这里缺少什么还是应该尝试不同的方法?任何想法最受欢迎:)

Testing with Glassfish 3.0.1 latest build - forgot to mention

使用 Glassfish 3.0.1 最新版本进行测试 - 忘了提及

回答by Brett Kail

The default @ConcurrencyManagement for singletons is ConcurrencyManagementType.CONTAINER with default @Lock of LockType.WRITE. Basically, that means every method (including generateReports) is effectively marked with the synchronized keyword, which means that checkQueueState will block while generateReport is running.

单例的默认 @ConcurrencyManagement 是 ConcurrencyManagementType.CONTAINER,默认 @Lock 是 LockType.WRITE。基本上,这意味着每个方法(包括 generateReports)都用 synchronized 关键字有效标记,这意味着 checkQueueState 将在 generateReport 运行时阻塞。

Consider using ConcurrencyManagement(ConcurrencyManagementType.BEAN) or @Lock(LockType.READ). If neither suggestion helps, I suspect you've found a Glassfish bug.

考虑使用 ConcurrencyManagement(ConcurrencyManagementType.BEAN) 或 @Lock(LockType.READ)。如果这两个建议都没有帮助,我怀疑您发现了 Glassfish 错误。

As an aside, you probably want persistent=false since you probably don't need to guarantee that the checkQueueState method fires every 5 seconds even when your server is offline. In other words, you probably don't need the container to fire "catch ups" when you bring your server back online.

顺便说一句,您可能需要persistent=false,因为即使您的服务器离线,您也可能不需要保证checkQueueState 方法每5 秒触发一次。换句话说,当您将服务器重新联机时,您可能不需要容器来触发“追赶”。