Основанные на времени события в ASP.net - PullRequest
9 голосов
/ 03 июня 2009

Мне нужно выполнить некоторые события (отправка электронных писем и т. Д.) В зависимости от времени. Каков наилучший способ сделать это в ASP.net в размещенной среде (со средним уровнем доверия)?

Пример: отправлять электронную почту каждый день в 16:00. Пример: отправить письмо через 15 минут после входа в систему.
Например: отправить письмо по истечении 10 часов с момента последнего изменения статуса.

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

Вот варианты, которые у меня есть ...

1) Таймер в Global.asax
+ Простой
- Не является надежным, веб-приложение может выгружаться в IIS и событие не будет запускаться.
? Возможно, используйте службу внешнего пингера, чтобы приложение оставалось в живых (надежно?)

2) Служба Windows для выполнения действия
- Проскользнуть / сохранить отдельный код.
- Не удается установить в размещенной среде (общий / облачный хостинг)

3) Служба Windows для вызова веб-приложения (вызывает веб-службу или запускает страницу)
+ Весь код в веб-приложении
- Не удается установить в размещенной среде.

4) Задание SQL Server для вызова веб-службы (через CLR)
? Не смотрел на это .. возможно? надежно в размещенной среде?

5) Таймер SQL Service Broker для добавления сообщения для вызова WebService (через CLR)
? Не смотрел на это .. возможно? надежно в размещенной среде?

6) Рабочий процесс Windows?
? Нет идей .. есть ли у этой технологии что-нибудь для этого?

Это кажется достаточно распространенной проблемой, существуют ли сторонние инструменты для решения этой проблемы?

Ответы [ 5 ]

1 голос
/ 15 августа 2013

Самый простой способ настроить запланированное задание в Windows, запустив простое консольное приложение или пакетный файл. http://windows.microsoft.com/en-us/windows7/schedule-a-task

Попытка сделать то, о чем вы говорите в IIS, имеет проблемы. Прочтите статью Фила Хаака о Опасности реализации повторяющихся фоновых задач в ASP.NET

1 голос
/ 12 ноября 2012

Я бы рекомендовал использовать задания SQL Server.

В нем есть все графики, необходимые для вашего решения, а также он очень надежен и может быть расширен с помощью кода C #.

1 голос
/ 03 июня 2009

У меня была такая же проблема, и я полностью согласен с вашим анализом. Мое лучшее решение на сегодняшний день - это приложение для внешнего планирования на компьютере, которым я управляю; это приложение запрашивает веб-страницу, которая на самом деле делает вещи.

Ужасно, но это работает, и я искал другие решения, поверьте мне!

0 голосов
/ 15 августа 2013

Если вы действительно хотите использовать ASP.NET, то для выполнения запланированных задач я бы использовал комбинацию кэширования SQL Server, WCF и ASP.NET. Вы можете легко изменить его, чтобы он выполнял более короткие или более длинные интервалы (например, ежечасно или еженедельно). Он будет выполнять только ежедневные задачи в выбранное время.

1. Настройка таблицы SQL для ваших задач

Column Name        Data Type   
Id                 int
Name               varchar(100) 
LastRun            datetime
Interval           int 
RunTime            datetime

2. Добавить некоторые данные в таблицу

1 
My Daily Email Task 
08/15/08 (old date)
300 (5 minutes)
09:00

Интервал в основном сообщает серверу, как часто нужно проверять время. Чем короче время, тем точнее будет время выполнения за счет необходимости чаще проверять базу данных.

3. При использовании ORM создайте сопоставление классов

public class Task
{
    public virtual int Id { get; set; }

    public virtual string Name { get; set; }

    public virtual DateTime? LastRun { get; set; }

    public virtual int Interval { get; set; }

    public virtual TimeSpan? RunTime { get; set; }
}

При этом используется свободный nhibernate. Entity Framework тоже отлично работает.

4. Создание вызовов службы для получения / сохранения задач

public Task[] GetTasks()
{

    var main = new Application.Main();
    using (var sessionFactory = main.SessionFactory)
    using (var session = sessionFactory.OpenSession())
    {
        return session.Query<Task>().ToArray();
    }

}

public bool SaveTask(Task task)
{
    var main = new Application.Main();
    using (var sessionFactory = main.SessionFactory)
    using (var session = sessionFactory.OpenSession())
    using (var trans = session.BeginTransaction())
    {
        session.SaveOrUpdate(task);
        trans.Commit();

        return trans.WasCommitted;
    }
}

Используется WCF для служебных вызовов. Технически, вам не нужен веб-сервис, но я думаю, что он помогает организации, когда вы храните запросы к базе данных отдельно от сайта ASP.NET.

5. Настройте планирование в своем файле global.asax

protected void Application_Start(object sender, EventArgs e)
{
    var service = new MyService.MyServiceClient();
    var tasks = service.GetTasks();

    foreach (var task in tasks)
    {
        AddTask(task);
    }

    service.Close();
}

Вышеприведенная функция в основном захватывает все задачи и помещает их в цикл кэширования.

private void AddTask(PortalService.Task task)
{
        var onCacheRemove = new CacheItemRemovedCallback(CacheItemRemoved);
        HttpRuntime.Cache.Insert(task.Name, task, null,
            DateTime.Now.AddSeconds(task.Interval), Cache.NoSlidingExpiration,
            CacheItemPriority.NotRemovable, onCacheRemove);
}

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

public void CacheItemRemoved(string k, object taskObj, CacheItemRemovedReason r)
{
    var task = (MyService.Task)taskObj;



    //Run the task if it is the next day and greater than or equal to the runtime
    if (task.LastRun.HasValue && task.LastRun.Value.Day != DateTime.Now.Day && task.RunTime.HasValue && task.RunTime.Value.Hours <= DateTime.Now.Hour && task.RunTime.Value.Minutes <= DateTime.Now.Minute))
    {
        RunTask(ref task);
    }


    //Add the task again so that this method gets called again
    AddTask(task);
}

Когда наш интервал истекает, вызывается указанная выше функция, которая запускает нашу задачу.

6. Создайте функцию, которая запускает логику ваших различных задач

        private void RunTask(ref PortalService.Task task)
        {

            var service = new MyService.MyServiceClient();

            switch (task.Name)
            {
                case "My Daily Email Task":
                    service.SendDailyEmail();
                    break;
                case "Another Daily Task":
                    service.DoAnotherOperation();
                    break;
                case "Yet Another Daily Task":
                    service.DoYetAnotherOperation();
                    break;
            }

            //Update the task to indicate that it ran
            task.LastRun = DateTime.Now;
            service.SaveTask(task);


            service.Close();
        }

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

0 голосов
/ 12 ноября 2012

Вы смотрели на кварцевый планировщик , он выполняет планирование работы. Это порт .Net версии Java. Смотрите эту статью о начале работы http://geekswithblogs.net/TarunArora/archive/2012/04/10/walkthrough-scheduling-jobs-using-quartz.net-ndash-part-1-what-is.aspx.

Мы также используем Azure и используем рабочие роли для запланированных задач. Вы можете увидеть эту статью здесь о создании основных запланированных задач с рабочими ролями Azure http://blog.smarx.com/posts/building-a-task-scheduler-in-windows-azure

В прошлом мы также настраивали веб-страницу, которая вызывает задачу, и использовали сервис, подобный https://www.pingdom.com/, для вызова страницы по расписанию.

...