1


Playを使用しています!バージョン1.2.4のフレームワーク
私のアプリケーションでは、いくつかのスケジュールされたジョブ(の子孫play.jobs.Job)を実装しました。

質問

実行時にこれらのジョブのスケジュールを変更できますか?

私自身の調査結果

一見すると、Playでのジョブスケジューリング!を介して実行されます。これは、公開されているplay.jobs.JobsPluginJDKのインスタンスを使用します。java.util.concurrent.ScheduledThreadPoolExecutorこれまでのところ、次のアプローチを考え出しました。スケジュールを変更するときは、エグゼキュータのスケジュールされたジョブを繰り返し、スケジュールを変更する必要があるジョブをキャンセルして、同じジョブ(より正確には同じクラスのジョブ)をスケジュールします。新しい設定。このようなもの:

for (final Object o: JobsPlugin.executor.getQueue())
{
    ScheduledFuture task = (ScheduledFuture) o;
    Job job = (Job) Java.extractUnderlyingCallable((FutureTask)task);
    if (MyJob.class == job.getClass())
    {
        task.cancel(true);
        new MyJob().every("2h");
        break;
    }
}

より良い解決策はありますか?ありがとう!

4

1 に答える 1

1

JobsPlugin 呼び出しを見ると、各ジョブ実行の最後にジョブの次の計画実行日が再計算されるため、ソリューションが機能するかどうかはわかりません。

これが私の解決策です。ジョブのcron属性に基づいてジョブの実行日を計算できるように、JobSchedulerクラスを再作成します。可視性ルールのために、いくつかのジョブ属性を再宣言する必要がありました。

だから私の仕事のクラスは

package jobs;

import java.util.Date;
import java.util.concurrent.ExecutorService;

import play.jobs.Job;

public class MyJob extends Job<Object> {

    public Date nextPlannedExecution = null;
    public String cron = null;

    @Override
    public void _finally() {
        // cron is null if we force job execution
        if (cron != null) {
            // As the job don't have a Cron annotation, super call does nothing
            super._finally();
            JobScheduler.scheduleForCRON(this, cron);
        }
    }

    void setExecutor(ExecutorService executor) {
        this.executor = executor;
    }
}

私のスケジューラ クラスはパッケージ ジョブです。

import java.util.Date;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;

import models.Partner;
import play.Logger;
import play.jobs.Job;
import play.jobs.JobsPlugin;
import play.libs.Expression;
import play.libs.Time.CronExpression;

public class JobScheduler {

    public static synchronized void scheduleCsvExportJob(String cron) {
        MyJob myJob = null;
        for (Job<?> job : JobsPlugin.scheduledJobs) {
            if (job instanceof MyJob) {
                myJob = (MyJob) job;
            }
        }
        if (myJob == null) {
            myJob = new MyJob();
            JobsPlugin.scheduledJobs.add(myJob);
        }
        myJob.cron = cron;
        scheduleForCRON(myJob, myJob.cron);
    }

    public static void scheduleForCRON(MyJob job, String cron) {
        try {
            Date now = new Date();
            cron = Expression.evaluate(cron, cron).toString();
            CronExpression cronExp = new CronExpression(cron);
            Date nextDate = cronExp.getNextValidTimeAfter(now);
            if (nextDate != null && !nextDate.equals(job.nextPlannedExecution)) {
                job.nextPlannedExecution = nextDate;
                JobsPlugin.executor.schedule((Callable<?>) job, nextDate.getTime() - now.getTime(),
                        TimeUnit.MILLISECONDS);
                job.setExecutor(JobsPlugin.executor);
            }
        } catch (Exception ex) {
            Logger.error(ex, "Cannot schedule job %s", job);
        }
    }
}

このコードを使用すると、JobScheduler.scheduleMyJob を呼び出して、適切なスケジューリング式を渡すことでジョブのスケジューリングを変更できます: 0 0 2 * * ? 2時間ごと。

ジョブが終了すると、_finally メソッドは、新しいスケジューリング時間を設定する scheduleForCRON メソッドを呼び出します。

たとえば、GUI ボタン​​を使用してジョブを強制的に実行する場合は、cron 属性を定義せずにインスタンスを作成できます。このインスタンスは最後に再スケジュールされません。

于 2012-09-24T05:44:57.173 に答える