Как стать автором
Обновить

Комментарии 49

Было бы интересно узнать о практическом применение таких менеджеров? Можете поделиться, в каких ситуациях вам приходилось их использовать?
Немного абстрактный пример — есть диспетчер, порождающий задачи и большое количество независимых друг от друга обработчиков, получающих атомарные задачи из очереди. При использовании таких менеджеров не нужно писать собственный сервис, раздающий задачи, что экономит довольно много времени.
Использовал Hangfire для управления задачами клиентских парсеров инстаграмма и для запуска всяческих процессов. Приложение на asp mvc.
(EN) -> Such as calculation schedulers, whereby one calculation depends on the completion of another calculation.

Such calculations could be for inserting aggregated data into analytics database etc. We discovered Quartz.NET and resolved this problem, we can pool all the calculations in our calc engine and they are ordered with a 'manual' inheritance tree via `Quartz.NET`.

Problem exists with thread failing, but that's another story.

Sorry for no RU.
Например, выполнение задач по-расписанию (загрузка новых данных, тяжелые скрипты по ночам). Или перенос с клиента в отдельный какой-либо ресурсоемкой задачи.
В бизнес-процессах повсеместно — раз в сутки скачать/отправить данные, проверить наличие данных в смежной системе, наличие информации от клиентов и так далее.
Есть сервис электронного документооборота DocuSign
У них есть систему нотификации о произошедших событиях, которая рассылает оповещения по заранее сконфигурированным url
Однако эта функция доступна только для пользователей с самой дорогой лицензией.
Если вы создаёте сервис, который интегрируется с DocuSign, то для пользователей с отключённой функцией оповещения вам придётся запрашивать какие данные изменились каждые 15 минут.
Таким образом после того, как пользователь в вашем сервисе авторизовался в DocuSign — вы с помощью HangFire можете поставить повторяющуюся каждые 15 минут задачу на опрос изменений
НЛО прилетело и опубликовало эту надпись здесь
Мы у себя используем RabbitMQ — в Nugget есть отличный клиент для .Net, разворачивается под linux за 3 клика, в win за… 4. Думаю, его можно добавить в опрос в качестве варианта ответа.
RabbitMQ это не планировщик. А средство доставки.
Да, прошу прощения, глаза зацепились за построение очереди. Тогда присоединяюсь к вопросу выше — было бы интересно узнать для каких задач нужен именно планировщик, а не система обмена сообщениями?
У нас на работе планировщик используется для периодического (от каждые 15 минут, до ежедневного или ежемесячного) сбора информации с различных источников (почта, ftp, api сайтов и т.д.).
Фактически куча ботов, которые умеют собираться информацию, затем боты которые обрабатывают и сохраняют.
Тоже самое работает и в обратном направлении, т.е. отправка.
Автоматизация повторяющихся действий, облегчение работы людей-менеджеров.
НЛО прилетело и опубликовало эту надпись здесь
Еще одним пример — организация ETL процесса, если нужно что-то более кастомное чем SSIS.
Хардкод конкретного метода конкретного класса с конкретным списком аргументов в конкретном порядке — лёгкий путь получить проблемы при обновлении системы. Почему-то разработчики подобных решений об этом не думают.
Возможный workaround: для повторяемых/отложенных задач хранить их id, далее при обновлении системы заменять задачи в БД новой версией.
Безусловно, проблема есть, но она решаема в разумные сроки.
UPD: вариантов решений вообще много, вплоть до переключения Hangfire-серверов на новый экземпляр базы данных Hangfire при апдейте системы, не прекращая поддержку старого, что логично.
Пока не столкнетесь, не оцените. У меня так в продуктиве однажды сдохли задачи, пусть и с другой системой хранений. Конвертировать такие сериализованные значения неудобно и даже не всегда можно, иногда старые записи должны работать по старому.
Просто имейте это в виду.
НЛО прилетело и опубликовало эту надпись здесь
Вообще-то hangfire не такой уж и бесплатный. У него есть Pro модификация в которой сейчас собственно и идет разработка, а бесплатный вариант не развивается.
Мы можем создать произвольное количество Hangfire-серверов и не думать об их синхронизации — Hangfire гарантирует, что одна задача будет выполнена одним и только одним сервером. Пример реализации — использование sp_getapplock (см. класс SqlServerDistributedLock).

Не гарантирует. Он (при организации расписания в sql) скрывает задачу из очереди на выполнение на 15 минут (по умолчанию, настраивается) а потом она появляется снова в очереди и может быть подхвачена другим сервером (или даже тем же самым). В результате хангфаер можно использовать только как планировщик задач, а управлять транзакционностью и т.п. приходится все равно снаружи. Вот и получается, что профит относительно quartz.net невелик.

Впрочем в качестве плюса можно отметить, что hangfire хорошо встраивается в asp.net приложения, не нужно следить за бекграунд потоками, в случае рестарта хоста корректно шлются завершающие сигналы во все запущенные потоки.
Впрочем в качестве плюса можно отметить, что hangfire хорошо встраивается в asp.net приложения, не нужно следить за бекграунд потоками, в случае рестарта хоста корректно шлются завершающие сигналы во все запущенные потоки.


Можно здесь подробней? Не совсем понятно какой тип задач в рамках ASP.NET сервера можно эффективно решать scheduler'om который привязан к таймеру, а не веб-запросу в качестве тригера.
К тому же Hangfire не имеет поддержки асинхронности, как я понимаю и на каждую задачу создает блокирующий long running background поток.
Зачем все это в хост веб приложения встраивать?
Можно здесь подробней? Не совсем понятно какой тип задач в рамках ASP.NET сервера можно эффективно решать scheduler'om который привязан к таймеру, а не веб-запросу в качестве тригера.

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

Я, честно говоря, последнее время считаю, что не нужно эти задачи встраивать в веб приложение и закладываю в архитектуру сразу отдельный сервис для бекграунд задач. Но это архитектуру усложняет и многие предпочитают хостить бекграунд задачи прямо в ASP.net приложении.
Простой планировщик не усложняющий архитектуру как-то слабо вяжется с распределенной системой имеющей persistance независимый от applicaton pool с очередью в базе в виде сериализованных .NET абстракций.
Ну так отдельный модуль, сепарированный, не требующий поддержки, легко встраиваемый. Если все это правда — он почти не усложняет архитектуру приложения, потому что его внутренняя архитектура никак не влияет на архитектуру приложения.
Вы хотите сказать, что длительная однократная задача (например, добавленная через BackgroundJob.Enqueue) может быть выполнена многократно? Как это воспроизвести? В моем случае, долговременные (2-4 часа) задачи выполняются строго 1 раз, иначе Hangfire было бы сложно воспринимать всерьез =)
Речь не совсем об этом. Не уверен что использовать в веб-сервере сторонние workers, хорошая идея. Даже несмотря на то, что там нету использования asp.net тред пула.
Вы пишите, что Web-интерфейс у Quartz.NET отсутствует. Не соглашусь. Он есть. Например github.com/guryanovev/CrystalQuartz
Спасибо, добавил ссылку в статью. Это проект от разработчиков Quartz.NET, или сторонний?
Сторонний
Есть еще:
1. QuartzNetWebConsole — bugsquash.blogspot.ru/2010/06/embeddable-quartznet-web-consoles.html и его исходники github.com/mausch/QuartzNetWebConsole
2. quartznet-admin — code.google.com/archive/p/quartznet-admin
Но я в своих проектах использовал только CrystalQuartz
Без БД (хранилища задач) Hangfire не работает и работать не может.

Может: MemoryStorage.
События можно создавать и обрабатывать в одном и том же процессе без каких-либо коннектов:
GlobalConfiguration.Configuration.UseMemoryStorage();

Масштабируемости и длительного хранения задач не будет, но иногда бывает удобно (например, удалять временные файлы с перепопытками в случае неудачи).
«И все-таки это хранилище!»
Безусловно.
Я просто добавил, что Hangfire можно использовать в очень простом виде (без SQL, Redis и отдельных процессов обработчиков). Даже дашборд работает.
chumakov-ilya, а с Microsoft HPC Pack technet.microsoft.com/ru-ru/library/jj899572.aspx можно использовать для таких целей, возможности не сравнивали?
С этой технологией не знаком, ничего сказать не могу.
Пользуюсь этим планировщиком около года, но только для мелких процессов которые нужно выполнять непосредственно на сервере приложения. Для реальных вычислительных процессов пользуюсь Azure Batch с автоматическим масштабированием (вычислительная мощность непосредственно на веб-сервере дорого обходится).

Одна неприятная особенность hangfire — каждый heartbeat это запись в базу данных. Если ведётся аудит базы, то он разрастётся очень быстро и может стать почти неподъёмным. Ещё трудней, если приложение развёрнуто в десятке разных окружений и соответственно для каждого окружения своя база данных. Поэтому я сделал отдельную базу данных для hangfire и подключил к ней все приложения с уникальными идентификаторами. В руководствах это описывается нечасто, но отделяйте зёрна от плевел, впоследствии будет легче.
Hangfire умеет работать с распределенными транзакциями, обрабатывать один таск сутки или более? Ожидать сигнала извне на каком-то этапе? Есть условные переходы по шагам тасков? Можно ли вообще делать последовательность или иерархию шагов, которые надо выполнить?
Hangfire это все же не энтерпрайз шина, а пакет, встраивающий в приложение возможность управления задачами. Планировщик и несколько очередей выполнения задач.
Понятно, спасибо.
Интересно, можно ла сравнить «планировщик задач» с «моделью акторов»? на первый взгляд кажется, что есть большое пересечение, например с AKKA.NET

Есть где то простой работающий пример установки и запуска простого теста на двух компьютерах для рассматриваемых планировщиков? без базы данных, без .ASP или windows сервисов?
Сравнить как равные альтернативы для решения одинаковых задач в общем нельзя.

Ну к примеру Hangfire без базы данных не работает в принципе. В базе данных он содержит очередь задач, вместе с непосредственно задачами и прочими инфраструктурными данными. То есть реально в базу данных записывается путь к исполняемому методу, название метода, типы параметров, сами параметры.

Абстрактный планировщик в вакууме может обойтись и без базы данных, но всё равно нужно будет где-то содержать расписание и историю исполнения.

Планировщик задач служит для того, чтобы можно было составить расписание (я хочу исполнять метод X каждое воскресенье в полночь с вот такими параметрами; хочу исполнять метод y через 10 минут после нажатия кнопки; и т.д), чтобы можно было посмотреть какое расписание есть на данный момент, и чтобы можно было посмотреть какие процессы уже исполнены и когда.

Акторы это грубо говоря модули, которые исполняются параллельно и бывает так, что взаимодействуют друг с другом (один актор, когда ему нужно, отсылает сообщение другому и тот другой обрабатывает сообщение в соответствии со своей логикой, не останавливая работу первого). Таким образом в процессе разработки планировщика задач вы скорее всего будете использовать модель акторов, это имеет смысл, это удобно.

Можно реализовать одинаковую функциональность с планировщиком и без планировщика, а можно сделать свой планировщик не зная что этот девайс так называется.
Просто в начале поста написано
С точки зрения клиента, работа с задачей происходит по принципу «fire-and-forget», а если точнее — «добавил в очередь и забыл» — на клиенте не происходит ничего…

Вот я и подумал, что это похоже на много чего, в том числе и AKKA.NET.

Теперь (в том числе и после вашего ответа) я понимаю, что тема поста все-таки инструменты, которые позволюят что то выполнить по некому событию.

Но есть тоглда другой вопрос: если мы заносим нечто, что должно выполняться раз в день и это нечно «восстанавливается» по Reflection, то получается любой апдейт части системы требует перезапуск очереди, что бы поместить в нее опять все те же задачи? Ведь типы могут измениться.
Я понимаю, с одной стороны это сильно облегчает программирование: любой метод засунул в «расписание» и он будет выполняться. С другой стороны, этот метод не может «долго» храниться.
Да, бывают такие случаи, когда вы занесёте в планировщик задачу с рефлектом, а потом обновите код программы. Обработка ошибок должна быть предусмотрена непосредственно в планировщике. В худшем случае тред будет оборван, а задача “зависнет” с каким-нибудь статусом. В лучшем случае, планировщик сможет словить ошибку, записать в результат, и перезапустить задачу максимум N раз (согласно настройкам планировщика).

Был у меня случай когда я использовал сущность из EF в качестве аргумента для задачи, отправленной в планировщик. Естественно, после обновления новый рантайм, и стало быть новые типы (особенность EF). Hangfire словил исключение, записал его, и так пять раз кряду, а потом забил, записав задачу как Failed. Мне, соответственно пришлось выяснить почему не работает функционал (спасибо тестерам), ну вот и закрутилось колесо дебага.

В общем-то “облегчает программирование” тут ни при чём. Ясное дело, что взять готовый инструмент и прикрутить его к вашему приложению — легче, чем написать инструмент с нуля или даже собрать его из каких-то модулей, но не в этом суть самого инструмента.

Вот вам юз-кейс:
Вы администратор. Ваша сеть расширилась и уже влом запускать бэкапы вручную. Вы пишете скрипт, который обращается в сеть, находит на данный момент включенные в сеть машины (у вас ведь могут быть и кочевые ноутбуки, и что угодно ещё), и отправляет их бэкапиться на ваш бэкап-сервер. Потом вы устанавливаете скрипт в крон бэкап серверу и вот у вас есть запланированная задача. Крон — это планировщик задач, он не облегчает жизнь разработчику ОС, он облегчает жизнь конечному пользователю, в данном случае администратору системы.

Планировщики задач существуют в большей степени не для того, чтобы “выполнить по некому событию”, а для того, чтобы “выполнить тогда, когда конечный пользователь укажет”. Иногда в бизнес-логике приложения бывают ситуации, когда это предрешено самой бизнес-логикой. Ну к примеру, у вас есть генератор отчётов и настройка времени действительности отчёта. Допустим отчёт действителен только в течение двух недель, а через две недели он теряет смысл. В приложении есть процедура генерации отчёта и процедура удаления отчёта. Генерация отчёта предусматривает занесение в планировщик задачи удаления конкретно этого отчёта через две недели. Процедура занесения задачи в планировщик предусмотрена разработчиком, но точное время исполнения назначает конечный пользователь при запросе нового отчёта. Всё для того, чтобы список результатов не раздувался за счёт устарелых данных. То есть опять же для облегчения жизни конечному пользователю.

В данном контесте «fire-and-forget» относится именно к пользователю. Он просто жмёт кнопку. Ему не нужно ждать, смотреть на полоску “loading” внизу окна браузера, пока метод вернёт результат. Метод исполнится тогда, когда для этого будет свободная мощность, примерно в то время, в которое положено, и пользователь об этом будет оповещён (с поправкой на дизайн интерфейса и логики метода). А пользователь может работать дальше и заниматься своими делами.
Я имею ввиду, что reflection позволяет не заморачиваться с построением специальных классов (которые наследуются от специальных интерфейсов) и легко и быстро добавлять «задачи» в очередь. Но, на мой взгляд, эти «задачи» могут быть актуальны только а рамках одного текущего билда программы. Хранить же «задачи» и использовать их в разных билдах выглядит очень опасно. Т.е. мы как бы не определяем API и значит не можем ни на что рассчитывать в следующем билде.

Так и есть, так и случается. Опасно, но не очень. В худшем случае — не будет исполнено. Ну если особый талант есть, то можно сделать так чтобы исполнить с ошибками, и тут начинается самая веселуха. Можно и данные напортить. Многое зависит от бизнес-логики приложения и от архитектуры. На старые задачи рассчитывать нельзя, а на новые — вполне можно. Естественно, можно предусматривать закрытие старых задач при создании нового рантайма, оповещение пользователей, и прочую инфраструктуру. Для того и есть архитектор приложения, чтобы этими вопросами заниматься, а разработчики — его информировать и внедрять эти решения. Да и в любом вопросе рефлексии идеальных решений нет, зыбкая область, нужно быть готовым ко всему.
Кмк, риск не больше, чем изменение схемы БД или контракта веб-сервиса. К такому нужно быть готовым, но и злоупотреблять не следует.
Был у меня случай когда я использовал сущность из EF в качестве аргумента для задачи, отправленной в планировщик. Естественно, после обновления новый рантайм, и стало быть новые типы (особенность EF). Hangfire словил исключение, записал его, и так пять раз кряду, а потом забил, записав задачу как Failed. Мне, соответственно пришлось выяснить почему не работает функционал (спасибо тестерам), ну вот и закрутилось колесо дебага.


Вообще-то автор хангфаера явно и четко пишет, что не рекомендуется использовать в качестве аргументов задачи объекты сложных типов. То есть по хорошему вам нужно было передать в него идентификатор сущности а саму сущность достать из бд в рамках задачи.
По-хорошему и переделал. Одно дело “не рекомендуется” и совсем другое “не получится, даже если очень захочешь”. Если честно, то я как старший должен был изучить документацию прежде, чем оставлять внедрение коллегам, но тут уж как вышло. Танцы на граблях хорошему учат.
Просто в начале поста написано
С точки зрения клиента, работа с задачей происходит по принципу «fire-and-forget», а если точнее — «добавил в очередь и забыл» — на клиенте не происходит ничего…

Вот я и подумал, что это похоже на много чего, в том числе и AKKA.NET.

Теперь (в том числе и после вашего ответа) я понимаю, что тема поста все-таки инструменты, которые позволюят что то выполнить по некому событию.

Но есть тоглда другой вопрос: если мы заносим нечто, что должно выполняться раз в день и это нечно «восстанавливается» по Reflection, то получается любой апдейт части системы требует перезапуск очереди, что бы поместить в нее опять все те же задачи? Ведь типы могут измениться.
Я понимаю, с одной стороны это сильно облегчает программирование: любой метод засунул в «расписание» и он будет выполняться. С другой стороны, этот метод не может «долго» храниться.

Зарегистрируйтесь на Хабре , чтобы оставить комментарий

Публикации

Истории