Как правильно реализовать паузу (таймаут) в фоновом или регламентном задании 1С

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей IT и автоматизация бизнеса
← На главную

При разработке регламентных заданий или механизмов интеграции часто возникает необходимость временно приостановить выполнение кода — для этого есть инструментарий отладки и управления регламентными заданиями. Это может потребоваться для ожидания освобождения файла, соблюдения лимитов запросов к внешним API (rate limiting) или для синхронизации нескольких параллельных процессов. В этой статье мы подробно разберем, как реализовать паузу в фоновом задании на платформе 1С:Предприятие 8.3, проанализируем различные методы и выберем наиболее оптимальные с точки зрения производительности сервера.

Проблема использования пустого цикла

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


КонецПаузы = ТекущаяДата() + 5; // Пауза 5 секунд
Пока ТекущаяДата() < КонецПаузы Цикл
    // Пустой цикл
КонецЦикла;

Почему так делать нельзя: В этот момент одно ядро процессора загружается на 100%, так как система непрерывно вычисляет текущую дату и сравнивает ее в бесконечном цикле. В фоновом задании это критично: если одновременно запустятся несколько таких заданий, сервер приложений может полностью "зависнуть". Мы же стремимся к тому, чтобы во время паузы поток "засыпал", освобождая ресурсы процессора для других задач.

Способ 1. Использование платформенного механизма ожидания (рекомендуемый)

Один из самых изящных и эффективных способов — использование метода ОжидатьЗавершения объекта ФоновоеЗадание — есть инструмент управления сеансами и регламентными заданиями. Идея заключается в том, чтобы заставить текущий поток ждать завершения другого (или самого себя), используя встроенный в платформу механизм таймаута.

Разберем пример реализации, который часто встречается в типовых конфигурациях:


Процедура ВыполнитьПаузу(Секунд)
    
    Попытка
        НаименованиеЗадания = "Пауза_" + Строка(Новый УникальныйИдентификатор());
        // Ищем заведомо несуществующее или специфическое задание
        Задания = ФоновыеЗадания.ПолучитьФоновыеЗадания(Новый Структура("Наименование", НаименованиеЗадания));
        
        Если Задания.Количество() > 0 Тогда
            Задания[0].ОжидатьЗавершения(Секунд);
        Иначе
            // Если заданий нет, мы можем использовать метод ожидания на пустом массиве
            // или вызвать ожидание для текущего процесса, поймав исключение по таймауту
            ФоновыеЗадания.ОжидатьЗавершения(Новый Массив, Секунд);
        КонецЕсли;
    Исключение
        // Исключение вылетит именно через указанное количество секунд (Таймаут)
        // Это штатное поведение для реализации паузы
    КонецПопытки;
    
КонецПроцедуры

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

Способ 2. Использование механизмов БСП

Если ваша конфигурация построена на базе Библиотеки Стандартных Подсистем (БСП), вам не нужно изобретать велосипед. В составе БСП уже есть готовые функции для организации паузы — подобное реализовано в универсальный инструмент администрирования 1С и управления заданиями. Рассмотрим их подробнее.

В зависимости от версии БСП, процедура может находиться в разных модулях:

Внутри этих методов используется аналогичный подход с ожиданием фонового задания. Важный нюанс: при использовании БСП для паузы может создаваться временное фоновое задание. Это занимает один сеанс (лицензию) и один поток в пуле фоновых заданий. Если на вашем сервере лимитировано количество одновременных заданий, массовое использование этого метода может создать очередь.

Способ 3. Системные команды Windows и Linux

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

Для Windows:
Команда timeout или ping. Вызов timeout через ЗапуститьПриложение выглядит так:


КомандаWindows = "timeout /t " + Формат(КоличествоСекунд, "ЧГ=0") + " /nobreak";
ЗапуститьПриложение(КомандаWindows, , Истина);

Однако у timeout есть недостаток — он может некорректно работать в сессиях без консоли. Более надежным считается старый добрый ping:


// Выполняем 5 запросов к локальному адресу, что занимает примерно 5 секунд
КомандаWindows = "ping -n 6 127.0.0.1 > nul";
ЗапуститьПриложение(КомандаWindows, , Истина);

Для Linux:
Если ваш сервер 1С работает на Linux, системная команда будет другой:

ЗапуститьПриложение("sleep 5", , Истина);

Это самый эффективный способ для Linux-серверов, так как утилита sleep является стандартной и потребляет ноль ресурсов во время ожидания.

Способ 4. Использование возможностей СУБД (SQL Server / PostgreSQL)

Если ваше фоновое задание выполняется в клиент-серверном варианте, мы можем переложить задачу ожидания на сервер базы данных. Это "чистый" метод, не требующий запуска внешних процессов или создания лишних фоновых заданий 1С.

Для Microsoft SQL Server:
Используем команду WAITFOR DELAY. Напишем код:


ЗапросSQL = "WAITFOR DELAY '00:00:05'"; // Пауза 5 секунд
// Выполняем запрос через ADO или внешние источники данных

Для PostgreSQL:
Здесь используется функция pg_sleep:

ЗапросSQL = "SELECT pg_sleep(5);"; // Пауза 5 секунд

Этот метод крайне эффективен, так как поток СУБД просто засыпает, не нагружая ни сервер приложений 1С, ни сервер базы данных.

Способ 5. Метод с HTTP-соединением (Кроссплатформенный)

Разберем еще один оригинальный способ, который работает везде (Windows, Linux, Docker). Мы создаем HTTPСоединение с несуществующим адресом и устанавливаем таймаут — для этого подойдёт мониторинг HTTP-соединений и соблюдения лимитов запросов.


Процедура ПаузаЧерезHTTP(Секунд)
    // Указываем заведомо не отвечающий IP в локальной сети
    Соединение = Новый HTTPСоединение("10.255.255.255", , , , , Секунд);
    Попытка
        Соединение.Получить(Новый HTTPЗапрос("/"));
    Исключение
        // Произойдет ожидание в течение 'Секунд' и выброс исключения по таймауту
    КонецПопытки;
КонецПроцедуры

Этот метод хорош тем, что он полностью опирается на штатные объекты 1С и предсказуемо ведет себя на любой операционной системе.

Выводы и рекомендации

Проанализировав все варианты, мы можем составить следующий рейтинг решений:

  1. Лучший выбор для типовых конфигураций: Использовать ОбщегоНазначения.Пауза() из БСП. Это стандарт индустрии.
  2. Лучший выбор для самописных баз: Метод с ФоновыеЗадания.ОжидатьЗавершения(). Он не требует внешних компонент и работает достаточно стабильно.
  3. Для высоконагруженных систем: Вызов pg_sleep (для Postgres) или WAITFOR DELAY (для MSSQL) через прямое соединение или внешние источники данных, чтобы минимизировать нагрузку на пул потоков 1С.
  4. Для Linux-серверов: Использование системной команды sleep через ЗапуститьПриложение.

Помните, что главная цель при реализации паузы — не дать процессору выполнять бесполезную работу. Выбирайте методы, которые переводят поток выполнения в режим ожидания на уровне ядра ОС или СУБД.

← На главную