Хитрый Quartz.NET Сценарий


Хорошо, немного фона здесь. У меня есть крупномасштабное веб-приложение (MVC3), которое делает все виды неважных вещей. Мне нужно, чтобы это веб-приложение имело возможность планировать ad-hoc Quartz.NET задания в базе данных Oracle. Затем я хочу, чтобы задания выполнялись позже через службуwindows . В идеале я хотел бы запланировать их запуск через равные промежутки времени, но с возможностью добавления заданий через веб-приложение.

В основном, желаемая архитектура является некоторой вариация этого:

Web-приложений Quartz.NET БД Quartz.NET службы Windows

То, что я закодировал до сих пор:

  • служба windows, которая (на данный момент) планирует и выполняет задания. Это, очевидно, не будет иметь место в долгосрочной перспективе, но мне интересно, могу ли я сохранить только это и изменить его, чтобы он в основном представлял оба ". Quartz.NET " s " на диаграмме выше.
  • веб-приложение (детали, я думаю, не очень важны здесь)
  • задания (которые на самом деле являются просто другой службой windows)

И пара важных замечаний:

  • он должен быть запущен из службы windows, и он должен быть запланирован через веб-приложение (чтобы уменьшить нагрузку на IIS)
  • приведенную выше архитектуру можно немного перестроить, предполагая, что вышеприведенный маркер все еще применим.

Теперь несколько вопросов:

  1. возможно ли это вообще?
  2. предполагая, что (1) проходит, что делать вы, ребята, думаете, что это лучшая архитектура для этого? Смотрите первую пулю на то, что я закодировал.
  3. Может ли кто-нибудь дать мне несколько методов Quartz, которые помогут мне запрашивать БД для выполнения заданий, когда они уже запланированы?

По этому вопросу будет назначена награда, как только она будет удовлетворена. Если ответ на вопрос будет удовлетворительным до этого, я все равно назначу награду за постер ответа. Так, во всяком случае, если вы дадите хороший ответ вот, ты получишь награду.

1 8

1 ответ:

Я попытаюсь ответить на ваши вопросы в том порядке, в котором они у вас есть.

  1. Да, это возможно сделать. На самом деле это обычный способ работы с Quartz.Net на самом деле, вы также можете написать ASP.Net приложение MVC, которое управляет Quartz.Net планировщики.

  2. Архитектура. В идеале и на высоком уровне, ваши приложения MVC будет использовать Quartz.Net API, чтобы соединиться с сервером quartz.net которая устанавливается в качестве службы Windows где-то. Quartz.Net использует удаленное управление для общайтесь удаленно, поэтому любые ограничения использования удаленного доступа применяются (например, он не поддерживается в Silverlight и т. д.). Quartz.Net предоставляет возможность установить его как службу windows из коробки, поэтому здесь действительно не так много работы, кроме настройки самой службы для использования (в вашем случае) AdoJobStore, а также включения удаленного доступа. Существует некоторая забота о том, как правильно установить службу, поэтому, если вы еще не сделали этого, посмотрите в этом посте.

Внутренне, в вашем приложении MVC вы захотите получить ссылку на планировщик и сохранить ее в виде синглтона. Затем в коде вы будете планировать задания и получать информацию о планировщике через этот уникальный экземпляр. Вы могли бы использовать что-то вроде этого:

public class QuartzScheduler
{
    public QuartzScheduler(string server, int port, string scheduler)
    {
        Address = string.Format("tcp://{0}:{1}/{2}", server, port, scheduler);
        _schedulerFactory = new StdSchedulerFactory(getProperties(Address));

        try
        {
            _scheduler = _schedulerFactory.GetScheduler();
        }
        catch (SchedulerException)
        {
            MessageBox.Show("Unable to connect to the specified server", "Connection Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
        }
    }
    public string Address { get; private set; }
    private NameValueCollection getProperties(string address)
    {
        NameValueCollection properties = new NameValueCollection();
        properties["quartz.scheduler.instanceName"] = "RemoteClient";
        properties["quartz.scheduler.proxy"] = "true";
        properties["quartz.threadPool.threadCount"] = "0";
        properties["quartz.scheduler.proxy.address"] = address;
        return properties;
    }
    public IScheduler GetScheduler()
    {
        return _scheduler;
    }
}

Этот код настраивает ваш Quart.Net клиент. Затем, чтобы получить доступ к удаленному планировщику, просто вызовите

GetScheduler()
  1. Запрос Вот пример кода, чтобы получить все задания из планировщик:

    public DataTable GetJobs()
    {
        DataTable table = new DataTable();
        table.Columns.Add("GroupName");
        table.Columns.Add("JobName");
        table.Columns.Add("JobDescription");
        table.Columns.Add("TriggerName");
        table.Columns.Add("TriggerGroupName");
        table.Columns.Add("TriggerType");
        table.Columns.Add("TriggerState");
        table.Columns.Add("NextFireTime");
        table.Columns.Add("PreviousFireTime");
        var jobGroups = GetScheduler().GetJobGroupNames();
        foreach (string group in jobGroups)
        {
            var groupMatcher = GroupMatcher<JobKey>.GroupContains(group);
            var jobKeys = GetScheduler().GetJobKeys(groupMatcher);
            foreach (var jobKey in jobKeys)
            {
                var detail = GetScheduler().GetJobDetail(jobKey);
                var triggers = GetScheduler().GetTriggersOfJob(jobKey);
                foreach (ITrigger trigger in triggers)
                {
                    DataRow row = table.NewRow();
                    row["GroupName"] = group;
                    row["JobName"] = jobKey.Name;
                    row["JobDescription"] = detail.Description;
                    row["TriggerName"] = trigger.Key.Name;
                    row["TriggerGroupName"] = trigger.Key.Group;
                    row["TriggerType"] = trigger.GetType().Name;
                    row["TriggerState"] = GetScheduler().GetTriggerState(trigger.Key);
                    DateTimeOffset? nextFireTime = trigger.GetNextFireTimeUtc();
                    if (nextFireTime.HasValue)
                    {
                        row["NextFireTime"] = TimeZone.CurrentTimeZone.ToLocalTime(nextFireTime.Value.DateTime);
                    }
    
                    DateTimeOffset? previousFireTime = trigger.GetPreviousFireTimeUtc();
                    if (previousFireTime.HasValue)
                    {
                        row["PreviousFireTime"] = TimeZone.CurrentTimeZone.ToLocalTime(previousFireTime.Value.DateTime);
                    }
    
                    table.Rows.Add(row);
                }
            }
        }
        return table;
    }
    

Вы можете просмотреть этот код на Github