К числу базовых «строительных блоков», которыми пользуются разработчики решений для SharePoint, относятся Timer Jobs. Вот уже много лет эти компоненты входят в состав базового продукта. Между прочим, запускаемые по расписанию задания применяют и сами специалисты Microsoft — для выполнения большинства длительных процессов, а также для создания элементов, осуществляющих трудоемкие операции. В качестве примера можно привести хотя бы агрегирование типов содержимого, в ходе которого используется ряд заданий для принудительной отправки типов содержимого. Кроме того, задания подписчиков позволяют типам содержимого распространяться до уровня сайта. Обычно с запускаемыми по расписанию заданиями нам приходится сталкиваться в ходе развертывания решения (WSP), ибо компоненты развертываются внутри SharePoint именно таким образом.

Процедура создания запускаемых по расписанию заданий не относится к числу простых; они выполняются из контекста базового процесса Internet Information Server (IIS), известного под названием w3wp.exe. В сущности, они выполняются внутри компонента, именуемого owstimer.exe, который сам по себе является отдельной службой. Задания Timer Jobs — неотъемлемая часть определенных категорий средств и функций, используемых внутри решений SharePoint.

Если мы откроем центр администрирования, то увидим список доступных запускаемых по расписанию заданий, именуемых Definitions (см. экран 1).

 

Список заданий, запускаемых по расписанию
Экран 1. Список заданий, запускаемых по расписанию

В центре администрирования имеется страница Timer Job Status, позволяющая проверить состояние того или иного запускаемого по расписанию задания, и страница Job Definitions, на которой пользователь может отредактировать определение запускаемого по расписанию задания. Кроме того, вы можете познакомиться с определениями заданий с целью просмотра списка всех запускаемых по расписанию заданий или просмотреть запланированные и выполняемые задания, для чего нужно щелкнуть мышью на состоянии задания.

На странице Timer Job Status вы можете, используя меню View, отфильтровать запускаемые по расписанию задания в соответствии с перечисленными ниже критериями.

  • All — отображаются все запускаемые по расписанию задания для соответствующей фермы.
  • Service — отображаются все запускаемые по расписанию задания для той или иной службы. Если вы изберете этот критерий, воспользуйтесь меню Service для выбора службы, по которой хотите отфильтровать указанные в списке задания.
  • Web Application — отображаются все запускаемые по расписанию задания для того или иного веб-приложения. Если вы выберете этот критерий, воспользуйтесь меню Web Application для выбора веб-приложения, по которому хотите отфильтровать указанные в списке задания.
  • Server — отображаются все запускаемые по расписанию задания для указанного сервера. Если вы укажете этот критерий, воспользуйтесь меню Server для выбора сервера, по которому хотите отфильтровать указанные в списке задания.
  • Job Definition — отображаются все запускаемые по расписанию задания для указанного определения задания. Чтобы вывести список этих определений, перейдите на страницу Timer Job Status и в меню Job Definition выберите пункт Change Job Definition.
  • Failed Jobs — отображаются все запускаемые по расписанию задания для данной фермы, выполнение которых завершилось аварийно.

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

Писать запускаемые по расписанию задания несложно. Надо просто продумать, какой именно код следует использовать и каковы границы дозволенного. Все запускаемые по расписанию задания проистекают из класса SPJobDefinition, который является достаточным основанием для формирования такого задания. Чтобы сформировать задание, привязанное к расписанию, нужно просто указать пустой класс и добавить следующие инструкции:

-using Microsoft.SharePoint;
-using Microsoft.SharePoint.Administration;

Далее базовый класс должен стать наследником класса SPJobDefinition. Его следует дополнить таким методом (если классу было присвоено имя CustomTimerJob), как показано в листинге 1.

Эти три метода определяют, куда пойдут наши настройки для запускаемого по расписанию задания. Далее нам нужно переопределить метод Execute; в него следует включить код, который будет выполнять все необходимые действия (это может быть код для выполнения трудоемких операций внутри SharePoint или других действий за пределами SharePoint). Но это еще не все, ведь класс сам по себе не будет выполнять никаких действий. Нам требуется дополнить проект неким средством (наряду с получателем ответа функции), чтобы мы могли ассоциировать запускаемое по расписанию задание с активируемым объектом.

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

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

Однако, если вы переходите на платформу Office 365, возникает проблема: вы не можете развертывать запускаемые по расписанию задания, поскольку они должны быть «решениями, имеющими полное доверие», а это не допускается. В таком случае вопрос состоит в следующем: как добиться аналогичной возможности, опираясь на Office 365?

Поскольку платформа Office 365 предусматривает использование служб Microsoft Azure Services, у нас появляется возможность, работая с обоими типами служб, получать результаты, которые дает применение запускаемых по расписанию заданий, с помощью заданий Azure Web Jobs.

В простейшей редакции задание Azure Web Job представляет собой консольное приложение, подгружаемое в операционную систему Azure; при этом обеспечивается выполнение в изоляции от текущего владельца и подключение к нашему подписчику Office 365. Задания Azure Web Jobs строятся на основе обычного консольного кода с одним исключением: в данном случае приходится добавлять для версии SharePoint Online ссылки DLL на стороне клиента, чтобы получить возможность подключения подписчика Office 365. При использовании продуктов Visual Studio мы можем добавлять пакет готовых кодов для комплекта App for SharePoint Web Toolkit (название может быть другим, так как компоненты переименовываются). В любом случае этот комплект инструментов необходим для нашего подключения. Далее нам нужно добавить подробные сведения по подписчику Office 365, такие как его Tenant URL, а также имя, используемое для регистрации в системе.

Для начала работы с кодом нам нужно просто указать ссылку Microsoft.SharePoint.Client, чтобы иметь возможность заходить на сайт с помощью кода, подобного приведенному в листинге 3 (демонстрационный код).

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

Процесс формирования заданий Azure Web Jobs хорошо документирован. Мы можем выбирать из большого числа различных типов заданий. На сайте Microsoft типы заданий Azure Web Job представлены в виде списка с примерами процедур формирования таких заданий. Однако основные этапы этого процесса таковы (см. экран 2):

  • формирование в операционной системе Azure веб-задания по запросу;
  • указание имени для задания;
  • определение порядка выполнения в соответствии с вашими потребностями;
  • отправка файла (в данном случае это будет файл с расширением exe, но также возможно использование файлов с расширениями cmd, bat, sh, py и js);
  • собственно формирование задания.

 

Формирование задания Azure Web Job
Экран 2. Формирование задания Azure Web Job

Выполнив процедуру добавления веб-задания, вы можете просто запустить его вручную или вернуться к нему и модифицировать таким образом, чтобы перевести его в категорию постоянных; это даст вам возможность запускать и останавливать процесс по своему усмотрению. Имейте в виду, что в нашем распоряжении всего два варианта действий. Если вы хотите получить конкретное расписание, можете воспользоваться механизмом Azure Scheduler, который позволяет выполнять тот же процесс, но одновременно дает возможность определять расписание выполнения (см. экран 3).

 

Создание расписания выполнения задания
Экран 3. Создание расписания выполнения задания

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

 

Указание даты запуска задания, времени и часового пояса
Экран 4. Указание даты запуска задания, времени и часового пояса

В случае использования других настроек планировщика вы можете создать особое расписание (см. экран 5).

 

Расширенные возможности настройки запуска задания
Экран 5. Расширенные возможности настройки запуска задания

Действуя в соответствии с приведенными выше рекомендациями, вы получите возможность с большей эффективностью управлять такими параметрами, как время и частота запуска консольного кода. Разумеется, поскольку все будет происходить в среде Office 365 и Azure, вы будете располагать превосходными средствами регистрации процесса.

Как видите, оба варианта великолепны: один для локальной версии, а другой — для Office 365. Что же касается выбора между ними, для меня вопрос ясен. Я действую по схеме, предложенной специалистами Microsoft: создаю в виде консольного приложения код, предназначенный для выполнения в определенное время, и решение практически готово к работе в «облачной» среде, когда организация перейдет на платформу Office 365.

Листинг 1. Создание базового класса
public CustomTimerJob():base()
{
}
public CustomTimerJob(string jobName, SPService service) : base(jobName, service, null, SPJobLockType.None)
{
}
public CustomTimerJob(string jobName, SPWebApplication webapp) : base(jobName, webapp, null, SPJobLockType.ContentDatabase)
{
}
Листинг 2. Добавление запускаемого по расписанию задания
CustomTimerJob job = new CustomTimerJob (JobName, site);
SPMinuteSchedule schedule = new SPMinuteSchedule();
schedule.BeginSecond = 0;
schedule.EndSecond = 59;
schedule.Interval = 15;
job.Schedule = schedule;
job.Update();
Листинг 3. Демонстрационный код для работы с Azure
var url = https://something.sharepoint.com // Tenant URL
var account = something@domain.com //Tenant Admin Email Address
var password = new SecureString();
password.AppendChar(«Pass@word1»); // Tenant Admin Password
ClientContext context = new ClientContext(url
context.AuthenticationMode = ClientAuthenticationMode.Default;
context.Credentials = new SharePointOnlineCredentials(account, password);