Quartz.NET - Работа не запускается? - PullRequest
5 голосов
/ 24 ноября 2010

Я пытаюсь реализовать Quartz.NET как службу Windows в C #. Мои работы не запускаются, когда я ожидаю, что они сработают ... вообще, насколько я могу судить?

У меня есть расписание My Job, которое запускается на следующую четную минуту после и запускается "поминутно". Однако, когда наступает следующая минута, я не могу сказать, работает ли что-нибудь на самом деле.

Я бы предположил, что при выполнении моей работы окно CLI будет отображаться при выполнении задания, и будут видны операции консоли (я даже добавил туда Console.ReadKey(), чтобы окно не открывалось и не закрывалось, поэтому быстро, я не могу видеть это), но, насколько я могу судить, график просто не выполняет задания.

Я заметил, что все время в UTC, и что StartTimeUtc будет установлено время UTC, которое составляет +6 часов от моего локального времени компьютера, но я также предположил бы, что планировщик кварца обрабатывает это, вычисляя время выполнения из моей настройки TimeZone, хотя у меня нет способа подтвердить это или подтвердить фактическое время, для которого установлено мое расписание.

Я предполагаю, что есть какой-то способ настроить сборку Common Logging и использовать ее, чтобы помочь мне узнать, каков мой статус, но мне еще предстоит выяснить, что с этим делать, чтобы включить какой-либо журнал для обратной связи с моей Windows Сервис, кроме записи в журнал событий, который я для него создал.

Моя функция OnStart моей службы Windows

protected override void OnStart(string[] args)
    {
        eventLog.WriteEntry("--- STARTING eLoyalty Scheduler Service ---");

        // construct a scheduler factory
        ISchedulerFactory schedFact = new StdSchedulerFactory();

        // get a scheduler
        IScheduler sched = schedFact.GetScheduler();

        // construct job info
        JobDetail jobDetail = new JobDetail("eLoyaltySchedulerService", null, typeof(PortalSchedulerJob));
        jobDetail.JobDataMap["jobSays"] = "eLoyalty Scheduler Service Executing!";
        jobDetail.JobDataMap["myStateData"] = new ArrayList(); 

        // fire every minute
        Trigger trigger = TriggerUtils.MakeMinutelyTrigger();

        // start on the next even minute
        trigger.StartTimeUtc = TriggerUtils.GetEvenMinuteDate(DateTime.UtcNow);

        // name it
        trigger.Name = "NextEvenMinute";

        // schedule it
        sched.ScheduleJob(jobDetail, trigger);

        // start the schedule
        sched.Start();

        eventLog.WriteEntry("--- STARTED eLoyalty Scheduler Service ---");
    }

Функция Execute () моей работы выглядит следующим образом:

public void Execute(JobExecutionContext context)
    {
        try
        {
            string instName = context.JobDetail.Name;
            string instGroup = context.JobDetail.Group;
            JobDataMap dataMap = context.MergedJobDataMap;
            string jobSays = dataMap.GetString("jobSays");
            ArrayList state = (ArrayList)dataMap["myStateData"];
            state.Add(DateTime.UtcNow);

            Console.WriteLine("Instance {0} of PortalSchedulerJob says: {1} @ {2}", instName, jobSays, DateTime.UtcNow);
            Console.ReadKey();
        }
        catch (JobExecutionException Ex)
        {
            throw Ex;
        }
    }

Если вы можете помочь мне выяснить, как устранить неполадки в моем действительном расписании, я могу решить это самостоятельно ...?

Ответы [ 5 ]

9 голосов
/ 25 ноября 2010

В задачах Quartz.NET вы должны вызывать только исключения JobExecutionException: Quartz.net - Урок 3 :

Метод Job.Execute (..) Наконец, мы нужно сообщить вам несколько деталей метод IJob.Execute (..). Единственный тип исключения, которое вам разрешено бросить из метода execute JobExecutionException. Потому что это, как правило, вы должны обернуть все содержимое метода execute с блоком try-catch. Вам следует также потратить некоторое время, глядя на документация для JobExecutionException, так как ваша работа может используйте его для предоставления планировщика различные директивы относительно того, как вы хотите исключение для обработки.

Вместо:

catch (JobExecutionException Ex)
{
   throw Ex;
}

Сделайте что-то вроде этого:

catch (Exception err)
{
    // Only allow JobExecutionException exceptions to be thrown...
    throw new Quartz.JobExecutionException(err);
}

Затем вы можете обработать исключение централизованно:

_globalJobListener = new GlobalJobListener();
sched.AddGlobalJobListener(_globalJobListener);


public class GlobalJobListener : Quartz.IJobListener
{
    public GlobalJobListener()
    {
    }

    public virtual string Name
    {
        get { return "MainJobListener"; }
    }

    public virtual void JobToBeExecuted(JobExecutionContext context)
    {       
    }

    public virtual void JobWasExecuted(JobExecutionContext inContext, JobExecutionException inException)
    {
        if (inException != null)
        {
            // Log/handle error here
        }
    }


    public virtual void JobExecutionVetoed(JobExecutionContext inContext)
    {

    }
}
2 голосов
/ 08 мая 2013

При отладке вы всегда можете запустить службу Windows в консоли:

static class Program
{
    static void Main()
    {
        var servicesToRun = new ServiceBase[] 
            { 
                new CassetteDeckService() 
            };

        if (Environment.UserInteractive)
        {
            var type = typeof(ServiceBase);
            const BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
            var method = type.GetMethod("OnStart", flags);

            foreach (var service in servicesToRun)
            {
                method.Invoke(service, new object[] { null });
            }

            Console.WriteLine("Service Started!");
            Console.ReadLine();

            method = type.GetMethod("OnStop", flags);

            foreach (var service in servicesToRun)
            {
                method.Invoke(service, null);
            }
            Environment.Exit(0);
        }
        else
        {
            ServiceBase.Run(servicesToRun);
        }
    }
}

Просто убедитесь, что изменили тип приложения на Консольное приложение в свойствах вашего проекта службы Windows (это не повлияет на его работу в качестве службы Windows, если она не запущена в интерактивном режиме).

0 голосов
/ 10 июня 2013

если вы хотите отладить свою работу, оставьте Visual Studio открытой, в коде вашей работы введите:

System.Diagnostics.Debugger.Launch ();

, что позволит вам подключиться к отладчику в visual studio и увидеть, что происходит.

в качестве альтернативы, если вы хотите, чтобы обычная регистрация работала, отправьте мне сообщение, поскольку у меня все отлично работает в моей службе Windows.

0 голосов
/ 30 ноября 2010

Спасибо всем за вход ... К сожалению, я не мог заставить это работать, но когда я добавил регистратор событий в свою функцию выполнения задания, я обнаружил, что он записывает в журнал событий каждую минуту каждую минуту как и ожидалось.

Я полагаю, что функции Console.WriteLine() и Console.ReadKey() ничего не делают в среде службы Windows?

ПРИМЕЧАНИЕ: они что-то делают, но в фоновом режиме работают как служба, а не в окне консоли ...

0 голосов
/ 24 ноября 2010

У нас были некоторые проблемы с пропуском триггеров. Я добавил глобальный прослушиватель триггера для отслеживания событий, связанных с выполнением заданий, который предоставил информацию, необходимую для устранения проблемы.

Мы также подключили NLog через Common.Logging, чтобы перехватить внутреннюю регистрацию Quartz (вы можете заметить, что мы Simple Logging Facade сами, так что этот компонент также настраивается здесь). Вот наш конфиг приложения, мы надеемся, что вы можете начать с него:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <configSections>
        <section name="quartz" type="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0,Culture=neutral, PublicKeyToken=b77a5c561934e089" />
        <section name="slf" type="Slf.Config.SlfConfigurationSection, slf"/>
        <sectionGroup name="common">
            <section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging" />
        </sectionGroup>
    </configSections>


    <quartz>
        <add key="quartz.threadPool.threadCount" value="20" />
        <add key="quartz.jobStore.misfireThreshold" value="420000" /><!-- 7 minutes -->
    </quartz>


    <slf>
        <factories>
            <factory name="nlog" type="SLF.NLogFacade.NLogLoggerFactory, SLF.NLogFacade"/>
        </factories>

        <loggers>
            <logger factory="nlog"/>
        </loggers>
    </slf>

    <common>
        <logging>
            <factoryAdapter type="Common.Logging.NLog.NLogLoggerFactoryAdapter, Common.Logging.NLog">
                <arg key="configType" value="FILE" />
                <arg key="configFile" value="~/NLog.config" />
            </factoryAdapter>
        </logging>
    </common>

</configuration>
...