Перейти к основному содержимому

Задания

Задания — это механизм, который позволяет выполнять заданный код асинхронно в фоновом режиме (фоновые задания) или по расписанию (запланированные задания). В «1С:Шине» задания описываются типами из пространства имен Стд::Задания.

Фоновые задания

С помощью фоновых заданий можно выполнять код на встроенном языке в фоновом режиме.

Фоновые задания описываются типом ФоновыеЗадания, который позволяет создавать задания и управлять ими.

Запуск фоновых заданий, выполняющих вычисления, с ожиданием завершения всех запущенных заданий
метод СозданиеФоновогоЗадания()
пер Задания = новый Массив<ФоновоеЗадание>()
Задания.Добавить(ФоновыеЗадания.Выполнить(&Расчеты.ПервыйРасчет))
Задания.Добавить(ФоновыеЗадания.Выполнить(&Расчеты.ВторойРасчет))
Задания.Добавить(ФоновыеЗадания.Выполнить(&Расчеты.ТретийРасчет))
ФоновыеЗадания.ОжидатьЗавершения(Задания)
;

Фоновое задание запускается при наличии ресурсов, однако результат его работы не гарантирован:

  • при выключении сервера или остановке приложения задание может не запуститься;
  • при выключении сервера, остановке приложения или прерывании работы выполняемые задания теряются.

Типичное применение фонового задания — параллельные вычисления.

Запланированные задания

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

Включение автозапуска запланированных заданий в настройках приложения

При включении сервиса в журнал событий записывается событие СобытиеЗапланированныеЗаданияВключены, а при выключении — СобытиеЗапланированныеЗаданияВыключены.

Запуск запланированного задания гарантируется в следующих случаях:

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

Создание и планирование заданий

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

Описание обработчика, который вызывается для выполнения задания
метод МойМетод(Ключ: Строка, Период: Число)
// код выполнения задания
;
Создание задания, запускающего метод МойМетод
знч Задание = ЗапланированныеЗадания.Создать(&МояПодсистема::МойМодуль.МойМетод, "Ключ", 500)

Метод Создать() возвращает объект типа СоздаваемоеЗапланированноеЗадание, который позволяет настроить создаваемое задание с помощью метода Настроить() и запланировать его выполнение относительно активной транзакции с помощью методов:

  • Запланировать() — если нет активной транзакции, задание планируется немедленно, в противном случае задание сохраняется в базу данных и планируется после завершения активной транзакции;
  • ЗапланироватьБезТранзакции() — задание планируется немедленно, независимо от наличия активной транзакции;
  • ЗапланироватьВТранзакции() — задание сохраняется в базу данных и планируется после завершения активной транзакции. Если активной транзакции нет, выбрасывается исключение.

Если сервис заданий выключен, метод ЗапланироватьБезТранзакции() выбрасывает исключение. Если сервис заданий выключен и активных транзакций нет, то методы Запланировать() и ЗапланироватьВТранзакции() выбрасывают исключение. При наличии активной транзакции методы Запланировать() и ЗапланироватьВТранзакции() успешно выполнятся, а задания будут запланированы, когда запустится сервис.

примечание

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

Изменение и настройка заданий

Метод Изменить() типа ЗапланированныеЗадания возвращает объект типа ИзменяемоеЗапланированноеЗадание, с помощью которого можно поменять некоторые параметры запуска существующего запланированного задания. Чтобы запланировать измененное задание, используются методы Запланировать(), ЗапланироватьБезТранзакции() и ЗапланироватьВТранзакции() по аналогии с одноименными методами типа СоздаваемоеЗапланированноеЗадание.

При настройке запланированного задания с помощью метода СоздаваемоеЗапланированноеЗадание.Настроить() вы можете задавать следующие параметры:

Ключ

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

  • изменить задание;

    // Создание запланированного задания НовоеЗадание с заданным ключом Ключ
    знч Ключ = "ЗаданиеРассылкиСпама"
    пер НовоеЗадание = ЗапланированныеЗадания.Создать(&МойМодуль.МойМетод)
    .Настроить(Ключ = Ключ)
    .Запланировать()

    // Получение объекта типа ИзменяемоеЗапланированноеЗадание,
    // чтобы изменить задание с ключом Ключ
    знч ИзмЗадание = ЗапланированныеЗадания.Изменить(Ключ)
  • отменить выполнение задания — прерывает исполнение задания, если оно выполняется в момент вызова; для задания с расписанием отменяется только текущее исполнение;

    ЗапланированныеЗадания.Отменить("МоеЗадание")
  • приостановить выполнение задания (только для заданий с расписанием);

    ЗапланированныеЗадания.Приостановить("МоеЗадание")
  • возобновить выполнение задания (только для заданий с расписанием).

    ЗапланированныеЗадания.Возобновить("МоеЗадание")

Ключ, назначенный с помощью метода Настроить(), удобно использовать для регулярных заданий. Если задание выполняется однократно, обычно используется уникальный автоматически сгенерированный ключ.

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

Параметр нельзя изменить после планирования задания.

Описание

Строка. Описание задания. Параметр нельзя изменить после планирования задания.

Расписание

Расписание|Обходимое<Расписание>. Задает расписание запуска задания.

Запуск задания в 8 утра 23 февраля и 8 марта
метод ЗапланироватьЗаданияСРасписанием()
знч Праздничное = ЗапланированныеЗадания.Создать(&МойМодуль.МойМетод)
Праздничное.Настроить(Расписание = [
Расписание.Ежемесячно(Время{8:00}, {Месяц.Февраль}, {23}),
Расписание.Ежемесячно(Время{8:00}, {Месяц.Март}, {8})])
Праздничное.Запланировать()
;

Задержка

Длительность. Задает задержку начала выполнения относительно времени планирования задания:

  • если задание запланировано с помощью метода ЗапланироватьБезТранзакции(), то задержка вычисляется от момента вызова этого метода;
  • если задание запланировано с помощью метода ЗапланироватьВТранзакции(), то задержка вычисляется от момента окончания активной транзакции;
  • если задано расписание, то задержка игнорируется.
Запуск задания с задержкой в 3 секунды
метод ЗапланироватьЗаданияСЗадержкой()
знч ЗаданиеСЗадержкой = ЗапланированныеЗадания.Создать(&МойМодуль.МойМетод)
ЗаданиеСЗадержкой.Настроить(Задержка = )
ЗаданиеСЗадержкой.Запланировать()
;

ПовторыПриОшибке

СтратегияПовтораЗадания. Используется, чтобы запланировать повторный запуск задания, если текущий запуск завершается с ошибкой.

ПовторыПриУспехе

СтратегияПовтораЗадания. Используется, чтобы запланировать повторный запуск задания при успешном завершении текущего запуска.

СтратегияПубликации

СтратегияПубликацииЗадания. Одновременно может существовать только один экземпляр запланированного задания с определенным ключом. С помощью перечисления СтратегияПубликацииЗадания вы можете выбрать стратегию публикации, которая будет действовать при попытке запланировать задание с существующим ключом:

  • Отбросить — отбросить новое задание и оставить существующее;
  • Перезапустить — отменить или прервать выполнение существующего задания и запустить новое.

Параметр нельзя изменить после планирования задания.

ХранениеРезультатов

СтратегияХраненияРезультатовЗаданий. Задает стратегию хранения результатов выполнения задания. Возможные значения:

Если известно время завершения сохраненного задания, можно воспользоваться методом ПолучитьРезультатыПоИнтервалу() типа ЗапланированныеЗадания.

Получение всех результатов выполнения задания за месяц
пер РезультатыПоИнтервалу = ЗапланированныеЗадания.ПолучитьРезультатыПоИнтервалу(
Момент.Сейчас()-30д,
Момент.Сейчас()
)
важно

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

примечание

Не следует сохранять результаты выполнения задания для отслеживания его работы. В этих целях используйте журнал событий.

ПриОшибкеПоследнегоПовтора

(РезультатЗадания)->ничто. Обработчик, который вызывается, если последний запуск задания завершается с ошибкой.

Если для задания указана стратегия повтора при ошибке, обработчик вызывается после окончания всех повторов. Если стратегия повтора при ошибке не настроена или используется значение по умолчанию СтратегияПовтораЗадания.Отсутствует(), то обработчик запускается после первой ошибки.

Параметр нельзя изменить после планирования задания.

Создание задания с обработкой ошибки
метод ЗапланироватьЗаданияСОбработкойОшибки()
знч СОбработкойОшибки = ЗапланированныеЗадания.Создать(&МойМодуль.МойМетод)

// Метод МойМодуль.МойОбработчикОшибки() вызывается,
// если запуск задания СОбработкойОшибки завершится с ошибкой
СОбработкойОшибки.Настроить(ПриОшибкеПоследнегоПовтора = &МойМодуль.МойОбработчикОшибки)
СОбработкойОшибки.Запланировать()
;

метод МойОбработчикОшибки(Результат: РезультатЗадания)
// Код обработчика результата с ошибкой
;

УсловияЗапускаНаМобильныхУстройствах

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

РегистрацияСобытий

СтратегияРегистрацииСобытийЗаданий. Задает стратегию регистрации событий в журнале событий:

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

Создание задания с регистрацией ошибок
метод СоздатьЗаданиеСРегистрациейОшибок()
знч Задание = ЗапланированныеЗадания.Создать(&МойМодуль.МойМетод)
Задание.Настроить(
Ключ = "МоеЗадание",
ХранениеРезультатов = СтратегияХраненияРезультатовЗаданий.Отсутствует(),
ПовторыПриУспехе = СтратегияПовтораЗадания.Интервал(),
ПовторыПриОшибке = СтратегияПовтораЗадания.Интервал(),
СтратегияПубликации = СтратегияПубликацииЗадания.Отбросить,
РегистрацияСобытий = СтратегияРегистрацииСобытийЗаданий.Ошибка
)
Задание.Запланировать()
;
Обновление задания с регистрацией ошибок
метод ИзменитьРегистрациюСобытийЗадания()
знч ЗаданиеСЗадержкой = ЗапланированныеЗадания.Изменить("КлючЗадания")
ЗаданиеСЗадержкой.Настроить(РегистрацияСобытий = СтратегияРегистрацииСобытийЗаданий.Ошибка)
ЗаданиеСЗадержкой.Запланировать()
;

Примеры работы с заданиями

  1. Создание и настройка задания

    Создание задания с периодическим запуском
    метод СозданиеЗаданий()
    знч Задание = ЗапланированныеЗадания.Создать(&МойМодуль.ОбработчикСозданияЗадания)
    Задание.Настроить(
    Ключ = "МоеЗапланированноеЗадание",
    ХранениеРезультатов = СтратегияХраненияРезультатовЗаданий.Отсутствует(),
    Расписание = Расписание.Периодическое(),
    СтратегияПубликации = СтратегияПубликацииЗадания.Отбросить)
    Задание.Запланировать()
    ;

    В этом примере планируется периодический запуск задания с периодом равным одной секунде. Если в момент вызова задание уже выполнялось или ожидало выполнения, то повторно оно не планируется. Результаты выполнения не сохраняются.

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

    • вызывать этот код при добавлении нового элемента справочника;
    • в обработчике задания обрабатывать записи, накопленные в справочнике на момент вызова;
    • за счет повторов реализуется обработка записей, добавленных во время работы предыдущей итерации.
  2. Запуск задания и изменение расписания существующего задания

    Создание задания и изменение его расписания
    метод СозданиеИНастройкаЗадания()
    знч Ключ = "ЗаданиеПраздничнойРассылки"

    пер НовоеЗадание = ЗапланированныеЗадания.Создать(&МойМодуль.МойМетод)
    НовоеЗадание.Настроить(
    Расписание = Расписание.Ежемесячно(Время{18:00}, {Месяц.Февраль}, {23}),
    Ключ = Ключ,
    Описание = "Праздничная рассылка"
    )
    НовоеЗадание.Запланировать()
    ;

    метод ИзменениеЗаданияПоКлючу(Ключ: Строка)
    знч ИзмЗадание = ЗапланированныеЗадания.Изменить(Ключ)
    если ИзмЗадание == Неопределено
    выбросить новый ИсключениеВыполнения("Нет задания с ключом %{Ключ}")
    ;

    ИзмЗадание.Настроить(Расписание = Расписание.Ежемесячно(Время{8:00}, {Месяц.Март}, {8}))
    ИзмЗадание.Запланировать()
    ;
  3. Планирование задания для реализации асинхронной подготовки состояния взаиморасчетов для внешних систем

    Внешние системы обращаются к приложению с помощью специального HTTP-сервиса. Они хотят получить состояние взаиморасчетов, подготовка которого занимает значительное время. Чтобы подготовка происходила асинхронно, реализуем ее с помощью запланированного задания, которое запускается в обработчике ЗапроситьДанные() HTTP-сервиса. Результаты по мере готовности отдаются в обработчике ЗапроситьРезультат().

    Результат описывается хранимой структурой СостояниеВзаиморасчетов. Логика вычисления возвращаемого набора данных описывается в методе ПодготовитьДанныеВзаиморасчетов() общего модуля МодульПодготовкиДанных.

    Общий модуль «МодульПодготовкиДанных»
    метод ПодготовитьДанныеВзаиморасчетов(Контрагент: Контрагент.Ссылка): СостояниеВзаиморасчетов
    // Вычисление возвращаемого набора данных
    ;
    Модуль HTTP-сервиса
    метод ЗапроситьДанные(Запрос: HttpServiceRequest)
    // Каждая внешняя система проходит аутентификацию,
    // обработчик выполняется от имени пользователя, соответствующего контрагенту
    знч СсылкаКонтрагента = ПолучитьКонтрагента(Пользователи.ТекущийПользователь)
    если СсылкаКонтрагента == Неопределено
    выбросить новый ИсключениеНедопустимыйАргумент()
    ;

    // Чтобы не выполнять одновременно несколько вычислений для одного контрагента,
    // формируем ключ задания из идентификатора контрагента и используем стратегию Отбросить.
    // Определяем предельный срок хранения результатов 1 день
    знч Задание = ЗапланированныеЗадания.Создать(&МодульПодготовкиДанных.ПодготовитьДанныеВзаиморасчетов, СсылкаКонтрагента)
    .Настроить(
    СтратегияПубликации=СтратегияПубликацииЗадания.Отбросить,
    Ключ = "BAL-%{СсылкаКонтрагента.Ид}",
    ХранениеРезультатов=СтратегияХраненияРезультатовЗаданий.Дней(1)
    )
    .Запланировать()
    Запрос.Ответ.УстановитьКодСтатуса(202)

    // Отдаем ключ задания, чтобы внешняя система могла узнать по нему результат,
    // и ожидаемый момент завершения
    пер ОтветСервиса = {"key": Задание.Ключ, "estimated-time": Момент.Сейчас() + }
    Запрос.Ответ.УстановитьТело(СериализацияJson.ЗаписатьОбъект(ОтветСервиса))
    ;

    метод ЗапроситьРезультат(Запрос: HttpServiceRequest)
    // Получаем ключ из параметра запроса
    знч Ключ = Запрос.Параметры.ПолучитьПервый("key")
    если Ключ == Неопределено
    выбросить новый ИсключениеНедопустимыйАргумент()
    ;

    // По ключу получаем последний результат задания
    знч Результат = ЗапланированныеЗадания.ПолучитьПоследнийРезультатПоКлючу(Ключ)

    // Если результата еще нет, пробуем получить описание задания
    // и устанавливаем соответствующий код статуса
    если Результат == Неопределено
    знч Задание = ЗапланированныеЗадания.ПолучитьПоКлючу(Ключ)
    Запрос.Ответ.УстановитьКодСтатуса(Задание == Неопределено ? 404 : 202)
    возврат
    ;

    // Если задание завершилось с ошибкой, записываем ее описание в ответ запроса,
    // если нет — записываем в ответ результат выполнения
    если Результат.Ошибка != Неопределено
    Запрос.Ответ.УстановитьКодСтатуса(500)
    Запрос.Ответ.УстановитьТело(Результат.Ошибка)
    иначе
    Запрос.Ответ.УстановитьТело(СериализацияJson.ЗаписатьОбъект(Результат.Результат))
    ;
    ;