0

SimpleTrigger を使用して、無期限に実行されるはずのジョブをスケジュールしています (繰り返し回数 -1)。

そして、JDBCストアを使用してジョブの状態をDBに永続化しています。

しかし、トリガーは一定の間隔で発火し (私の場合は常に 8)、BLOCKED 状態になります。具体的には、QRTZ_TRIGGERS テーブルで TRIGGERS_STATE の値が BLOCKED に変更されます。Quartx テーブルのプレフィックスは QRTZ_ であることに注意してください。以下は私のジョブ トリガー情報です。

繰り返し回数:-1、繰り返し間隔:6秒、開始遅延:10秒

私のクォーツ構成:

#===============================================================
#Configure ThreadPool
#===============================================================
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 10
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
#===============================================================
#Configure JobStore
#===============================================================
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.maxMisfiresToHandleAtATime=20
# Flag to turn off to ignore all misfires
scheduler.ignoreMisfire=no

# Configuring JDBCJobStore with the Table Prefix
org.quartz.jobStore.tablePrefix = QRTZ_

# Using DriverDelegate
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
org.quartz.jobStore.useProperties = false

スケジューラ クラス:

public static void scheduleJob(Class<? extends Job> job,JobDataMap dataMap) 
{

    Scheduler scheduler = schedulerFactoryBean.getScheduler();
    try
    {
        JobDetail jobDetail = newJob(job)
                .withIdentity(job.getSimpleName()+"_"+DateUtil.getSystemDate(), job.getSimpleName() + "_group")
                .storeDurably()
                .usingJobData(dataMap)
                .requestRecovery()
                .build();

        SimpleTrigger trigger = (SimpleTrigger) newTrigger()
                .withIdentity(job.getSimpleName() + "_trigger_"+DateUtil.getSystemDateWithMs(), job.getSimpleName() + "_trigger_group")
                .startNow()                 
                .withSchedule(simpleSchedule().repeatSecondlyForever(10).withMisfireHandlingInstructionFireNow())
                .build();

        scheduler.scheduleJob(jobDetail, trigger);

        //logger.debug(scheduler.getMetaData().toString());
        scheduler.start();
    }
    catch (SchedulerException e)
    {
        e.printStackTrace();
        throw new SchedulerException("", e);
    }
}

ジョブ クラス:

@PersistJobDataAfterExecution
public class MyJob  Implements Job
{
    private SessionFactory sessionFactory;

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException
    {
        getBeansFromContext(context);
        Session session = sessionFactory.openSession(); // Hibernate Session Factory
        // to do some DB opetations
    }

    private void getBeansFromContext(JobExecutionContext context) throws SchedulerException
    {
        ApplicationContext applicationContext = (ApplicationContext)context.getScheduler().getContext().get("applicationContext");
        this.sessionFactory=applicationContext.getBean(SessionFactory.class);
    }
}

Quartz スケジューラーファクトリーの Spring Bean 構成。

<beans:bean id="schedulerFactoryBean"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<beans:property name="jobFactory">
    <beans:bean class="org.springframework.scheduling.quartz.SpringBeanJobFactory"></beans:bean>
</beans:property>
<beans:property name="dataSource" ref="dataSource" />
<beans:property name="transactionManager" ref="txManager" />
<beans:property name="configLocation"
    value="resources/scheduler/Scheduler.properties" />
<beans:property name="applicationContextSchedulerContextKey"
    value="applicationContext" />
<beans:property name="autoStartup" value="true" />
</beans:bean>

<beans:bean id="taskExecutor"
class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"
p:corePoolSize="5" p:maxPoolSize="10" p:queueCapacity="100"
p:waitForTasksToCompleteOnShutdown="true" />

どんな助けでも本当に感謝しています。前もって感謝します

4

2 に答える 2

2

私は最終的に問題を理解し、それを解決することができました。

@zerologiko がコメントしたように、問題はトランザクションにあります。休止状態でSpringマネージドトランザクションを使用しています。トランザクション ポリシーを宣言すると、Spring がトランザクションの開始/終了を処理します。

私の場合の問題の理由:Spring Bean のライフ サイクルは、スケジューラ ジョブでは有効ではありません。これについて詳しく説明するために、メインの投稿にあるように、ジョブ クラス内で applicationContext にアクセスする必要さえありました。

jobContext.getScheduler().getContext().get("applicationContext");

ジョブが完了した後、DB を何らかのステータスでトランザクション データベースの 1 つに更新しようとしています。

トランザクションも Spring によって制御されていることに最初は気付きませんでした。これらのデータベースの更新がジョブ クラスからトリガーされた場合、ビジネス メソッドで宣言されたトランザクションは効果がありませんでした。

私の理解によると、ジョブを完了したスレッドがプールに戻ることができないため、トリガーは取得されました。

この問題を解決するために、Spring CMT に依存せずにジョブ クラスのトランザクションを手動で開いたり閉じたりしましたが、問題なく動作しました。

これが同じ種類の問題に直面している人に役立つことを願っています。

于 2013-10-02T15:37:04.093 に答える
0

CRON トリガーで同様の問題が発生しましたが、根本的な原因も Spring 管理トランザクションが原因です。

ただし、問題を解決するために私が行ったことは、あなたのものとは少し異なります。

コード レベルで @Transactional アノテーションを保持し、代わりに、Spring の介入なしに独自の DB 操作に使用する Quartz 用の専用の dataSource を構成しました。

 <!-- Datasource used by Quartz -->
<bean id="quartzDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="${db.driver}"/>
    <property name="url" value="${db.url}"/>
    <property name="username" value="${db.user}"/>
    <property name="password" ref="dbPassword"/>
    <property name="maxActive" value="${db.conn.pool.maxActive:30}"/>
    <property name="maxIdle" value="${db.conn.pool.maxIdle:15}"/>
    <property name="minIdle" value="${db.conn.pool.minIdle:0}"/>
</bean>
<!-- Datasource used by Quartz --> 


 <!-- Assign an dedicated dataSource to quartz scheduler-->
 <bean id="cronJobScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="configLocation" value="classpath:META-INF/quartz/quartz.properties"/>
    <property name="jobFactory" ref="springBeanJobFactory"/>
    <property name="dataSource" ref="quartzDataSource"/>
 </bean>
于 2016-02-24T07:21:30.713 に答える