Отладка на сервере 1С 8.3 нужна, когда ошибка живёт в серверном коде клиент-серверной базы: в проведении, регламентном задании, HTTP-сервисе для сайта. В файловой базе такой код ловится обычным F5, а в клиент-серверной точки останова молча пропускаются, пока агент сервера не запущен с ключом -debug. Ниже — служба Windows и systemd, TCP и HTTP, порты, подключение из конфигуратора, фоновые задания и модуль-помощник. Точки останова, табло и стек вызовов разобраны в статье «Отладка 1С 8.3».
Отладчик подключается к процессу, где выполняется код, а это почти никогда не компьютер разработчика:
| Что отлаживаем | Где выполняется код | Что включить |
|---|---|---|
| &НаСервере, модули объектов и менеджеров | рабочий процесс rphost | агент с -debug |
| Фоновые и регламентные задания | rphost, отдельный сеанс | -debug и автоподключение заданий |
| HTTP-, веб- и OData-сервисы | rphost; у файловой базы — модуль веб-сервера | -debug или отладка в публикации |
Режим отладки задаёт агент ragent и передаёт его менеджеру кластера rmngr и рабочим процессам rphost. Ключи читаются при старте службы, а перезапуск рвёт все сеансы кластера — делайте его в нерабочее время.
| Ключ ragent | Что делает |
|---|---|
-debug | включает отладку; без уточнения протокола — TCP/IP |
-tcp, -http | протокол отладки; HTTP-отладка появилась в 8.3.7 |
-debugServerPort <порт> | порт сервера отладки кластера, по умолчанию 1550 |
-debugServerAddr <адрес> | сетевой интерфейс, на котором он слушает |
-debugServerPwd <пароль> | пароль на подключение к серверу отладки |
С -debug -http агент сам запускает сервер отладки кластера — дочерний процесс dbgs.exe --port=1550, который слушает все интерфейсы. С одним -debug рабочие процессы стартуют с -debug -tcp: так выглядит большинство серверов, где отладку «когда-то включили».
Служба называется «1C:Enterprise 8.3 Server Agent (x86-64)» (в оснастке — «Агент сервера 1С:Предприятия 8.3 (x86-64)»), её командная строка лежит в параметре ImagePath ключа HKLM\SYSTEM\CurrentControlSet\Services\<имя службы>. Скрипт надёжнее regedit: не теряет кавычки вокруг путей с пробелами и сохраняет исходную строку. Чтобы выключить отладку, оставьте только первую замену.
# PowerShell от имени администратора на сервере 1С
$name = "1C:Enterprise 8.3 Server Agent (x86-64)" # все агенты: Get-Service "1C*"
$key = "HKLM:\SYSTEM\CurrentControlSet\Services\$name"
$old = (Get-ItemProperty -Path $key -Name ImagePath).ImagePath
$old | Out-File "$env:TEMP\ragent-imagepath.txt" # копия исходной строки
# убрать прежние ключи протокола и вставить -debug -http сразу после ragent.exe
$new = $old -replace '\s-(debug|http|tcp)\b', ''
$new = $new -replace '(ragent\.exe"?)', '$1 -debug -http'
Set-ItemProperty -Path $key -Name ImagePath -Value $new
Restart-Service -Name $name -Force # сеансы кластера будут разорваны
(Get-CimInstance Win32_Service -Filter "Name='$name'").PathName
# "C:\Program Files\1cv8\8.3.27.1786\bin\ragent.exe" -debug -http -srvc -agent -regport 1541 ...
# порт сервера отладки кластера: только для подсети разработчиков
New-NetFirewallRule -DisplayName "1C Debug Server" -Direction Inbound -Protocol TCP `
-LocalPort 1550 -RemoteAddress 192.168.10.0/24 -Action Allow
То же из cmd через sc.exe — кавычки внутри значения экранируются обратной косой чертой:
rem cmd от имени администратора; пробел после binPath= обязателен
sc config "1C:Enterprise 8.3 Server Agent (x86-64)" binPath= "\"C:\Program Files\1cv8\8.3.27.1786\bin\ragent.exe\" -debug -http -srvc -agent -regport 1541 -port 1540 -range 1560:1591 -d \"C:\Program Files\1cv8\srvinfo\""
net stop "1C:Enterprise 8.3 Server Agent (x86-64)"
net start "1C:Enterprise 8.3 Server Agent (x86-64)"
После обновления платформы проверьте ImagePath снова — ключ отладки легко потерять. Установка сервера и порты кластера — в статье «Установка сервера 1С 8.3».
В юните srv1cv8-<версия>@.service ключи агента вынесены в переменные окружения, за отладку отвечает SRV1CV8_DEBUG: пусто — выключено, -debug — включено. Юнит меняется при обновлении платформы, поэтому переменную задают drop-in-файлом:
# Linux с systemd; версию платформы и имя экземпляра подставьте свои
V=8.3.27.1786
UNIT=srv1cv8-$V@default.service
systemctl cat $UNIT | grep -E 'SRV1CV8_DEBUG|ExecStart' # как юнит передаёт ключ
sudo mkdir -p /etc/systemd/system/$UNIT.d
sudo tee /etc/systemd/system/$UNIT.d/debug.conf > /dev/null <<'EOF'
[Service]
Environment="SRV1CV8_DEBUG=-debug -http"
EOF
sudo systemctl daemon-reload
sudo systemctl restart $UNIT
pgrep -a ragent # в строке запуска должны быть -debug -http
# порт сервера отладки кластера (firewalld; для ufw: sudo ufw allow 1550/tcp)
sudo firewall-cmd --permanent --add-port=1550/tcp && sudo firewall-cmd --reload
Кавычки в Environment= обязательны: без них systemd сочтёт -http отдельным присваиванием. Если в ExecStart переменной нет, переопределите сам ExecStart — пустой строкой ExecStart= и полной командой с -debug -http. В старых установках с init-скриптом srv1cv83 отладку включает SRV1CV8_DEBUG=1 в /etc/sysconfig/srv1cv83 или /etc/default/srv1cv83.
Протокол сервера и конфигуратора должен совпадать. В конфигураторе он задаётся в «Сервис → Параметры → Отладка», поле «Протокол отладки» (в актуальных версиях по умолчанию HTTP), и применяется после перезапуска конфигуратора.
| TCP/IP | HTTP | |
|---|---|---|
| Ключи агента | -debug | -debug -http |
| Как связываются | отладчик сам ищет предметы отладки по диапазону портов | через сервер отладки dbgs |
| Автоподключение | по типам; в файловой базе — только фоновые задания | по типам и отборам: пользователи, разделители |
| Инструменты | конфигуратор | конфигуратор и EDT |
Для нового сервера берите HTTP: один порт вместо диапазона, отбор по пользователю, EDT.
-debugServerPort) — откройте его только для подсети разработчиков.-range кластера (обычно 1560:1591).В файловой базе -debug не нужен: серверный код выполняется в процессе клиента, и F5 отлаживает его сразу. Особых случаев три.
/AllowExecuteScheduledJobs -Off, а -Force передаёт их нужному сеансу — первая команда листинга плюс автоподключение фоновых заданий.debug в default.vrd (в url — адрес сервера отладки) и перезапускают веб-сервер. Подробнее — в статье о публикации 1С на веб-сервере.Debug и DebuggerURL.# Файловая база: отладочный клиент, которому переходят регламентные задания.
# Адрес сервера отладки возьмите из «Отладка → Подключение → Настройки».
"C:\Program Files\1cv8\8.3.27.1786\bin\1cv8c.exe" /F "D:\Bases\buh" /Debug -http -attach /DebuggerURL "http://localhost:1550" /AllowExecuteScheduledJobs -Force
# Клиент тестировщика к серверной базе: регистрируется на сервере отладки кластера
"C:\Program Files\1cv8\8.3.27.1786\bin\1cv8c.exe" /S "srv01\buh" /Debug -http -attach /DebuggerURL "http://srv01:1550"
<!-- default.vrd публикации файловой базы: отладка по HTTP -->
<point xmlns="http://v8.1c.ru/8.2/virtual-resource-system"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
base="/buh" ib="File="D:\Bases\buh";">
<!-- прочие элементы публикации оставьте как есть -->
<debug enable="true" protocol="http" url="http://localhost:1550"/>
</point>
| Что ловим | HTTP: тип предмета | TCP: флажок |
|---|---|---|
| Серверный код сеансов | Сервер | Клиентские и внешние соединения на сервере |
| Фоновые и регламентные задания | Фоновое задание | Фоновые задания |
| HTTP-сервисы | HTTP-сервис | HTTP-сервисы |
| Веб-сервисы | Web-сервис | Web-сервисы |
| OData | Стандартный интерфейс OData | OData-сервисы |
| Внешнее соединение | COM-соединение | Клиентские и внешние соединения на сервере |
Свой сеанс, запущенный по F5 в HTTP-режиме, отмечать не нужно. «Отборы предметов отладки» (только HTTP) ограничивают автоподключение пользователями — на общем сервере вы не остановите чужие задания.
Фоновое задание видно в списке предметов, только пока выполняется, поэтому вручную его не поймать. Порядок такой:
-debug, протоколы совпадают, конфигуратор открыт на базе.ВыполнитьДляОтладки из листинга ниже.На копии рабочей базы часто включена блокировка регламентных заданий — запускайте метод вручную. Задание работает от имени указанного в нём пользователя, ошибки прав воспроизводите под ним. Создание и запуск заданий из кода — в статьях о регламентных и о фоновых заданиях.
В HTTP-режиме нужны агент с -debug -http, открытый на сервере порт 1550 и сервер отладки кластера в настройках конфигуратора. Пароль из -debugServerPwd вводят в окне «Доступ к серверу отладки» или в группе «Доступ» вкладки «Отладка». Клиент тестировщика запускают второй командой листинга выше: с -attach отладчик сам подключит его клиентскую и серверную части. В TCP-режиме отметьте в окне подключения «Искать предметы отладки на удаленном компьютере» и укажите сервер.
Реестру не верьте на слово — смотрите ключи работающих процессов:
# Windows: с какими ключами реально работают агент, рабочие процессы и сервер отладки
Get-CimInstance Win32_Process -Filter "Name='ragent.exe' OR Name='rphost.exe' OR Name='dbgs.exe'" |
Select-Object ProcessId, ParentProcessId, CommandLine | Format-List
# rphost.exe ... -debug -tcp отладка по TCP
# rphost.exe ... -debug -http отладка по HTTP, рядом dbgs.exe --port=1550
Get-NetTCPConnection -State Listen -LocalPort 1550 -ErrorAction SilentlyContinue
# с компьютера разработчика: порт доступен и сервер отладки отвечает
Test-NetConnection srv01 -Port 1550
(Invoke-WebRequest -UseBasicParsing "http://srv01:1550/").Content
# <html>1C:Enterprise 8.3 Debug Server (8.3.27.1786) ... - it works!</html>
# Linux: то же через ps и ss
ps -eo pid,args | grep -E '[r]agent|[r]phost|[d]bgs'
sudo ss -ltnp | grep ':1550'
-debug -tcp или -debug -http — отладка включена, протокол виден сразу;dbgs.exe --port=1550, а запрос к порту возвращает строку «1C:Enterprise 8.3 Debug Server … - it works!».Общий модуль пишет в журнал регистрации, где выполняется код, держит паузу до подключения отладчика и одной функцией запускает метод в текущем сеансе или фоном.
// Общий модуль ОтладкаНаСервере: флажок «Сервер», без «Вызов сервера», не глобальный.
// Помощник для отладки серверного кода, фоновых и регламентных заданий. Платформа 8.3.13+.
// Где выполняется код: по номеру сеанса и компьютеру нужный предмет отладки
// легко найти в окне «Отладка → Подключение».
Функция ОписаниеСеанса() Экспорт
Сеанс = ПолучитьТекущийСеансИнформационнойБазы();
Описание = СтрШаблон("сеанс %1 (%2), сервер %3, пользователь ""%4""",
XMLСтрока(Сеанс.НомерСеанса), ПредставлениеПриложения(Сеанс.ИмяПриложения),
ИмяКомпьютера(), ИмяПользователя());
Задание = Сеанс.ПолучитьФоновоеЗадание();
Если Задание <> Неопределено Тогда
Описание = Описание + СтрШаблон(", задание ""%1"" %2", Задание.Наименование, Задание.УникальныйИдентификатор);
КонецЕсли;
Возврат Описание;
КонецФункции
// Включает ожидание отладчика для метки на заданное число минут (0 - выключить).
// Флаг хранится в настройках пользователя, от имени которого работает задание
// или HTTP-сервис; для чужого пользователя нужны административные права.
// Функция, а не процедура: её можно вызвать из окна «Вычислить выражение».
Функция ВключитьОжидание(Метка, ИмяПользователяИБ = "", Минут = 30) Экспорт
Срок = ?(Минут > 0, ТекущаяУниверсальнаяДата() + Минут * 60, Дата(1, 1, 1));
Если ПустаяСтрока(ИмяПользователяИБ) Тогда
ХранилищеОбщихНастроек.Сохранить("ОтладкаНаСервере", Метка, Срок);
Иначе
ХранилищеОбщихНастроек.Сохранить("ОтладкаНаСервере", Метка, Срок, , ИмяПользователяИБ);
КонецЕсли;
Возврат Срок;
КонецФункции
// Пауза до подключения отладчика. Точку останова ставят на строку
// с ОжидатьЗавершенияВыполнения; после остановки в окне «Локальные переменные»
// задайте Ждать = Ложь (команда «Установить новое значение в виде выражения»).
Процедура ЖдатьОтладчик(Метка, МаксимумСекунд = 120, Принудительно = Ложь) Экспорт
Если Не Принудительно И Не ОжиданиеВключено(Метка) Тогда
Возврат;
КонецЕсли;
ЗаписьЖурналаРегистрации("ОтладкаНаСервере.Ожидание", УровеньЖурналаРегистрации.Предупреждение, , ,
СтрШаблон("[%1] ждём отладчик до %2 с: %3", Метка, МаксимумСекунд, ОписаниеСеанса()));
Таймер = ПолучитьТекущийСеансИнформационнойБазы().ПолучитьФоновоеЗадание();
Вспомогательное = (Таймер = Неопределено);
Если Вспомогательное Тогда
// Сеанс не фоновый (HTTP-сервис, клиент): ждём служебное задание-паузу
ПараметрыПаузы = Новый Массив;
ПараметрыПаузы.Добавить(МаксимумСекунд);
Таймер = ФоновыеЗадания.Выполнить("ОтладкаНаСервере.Пауза", ПараметрыПаузы, , "Отладка: пауза " + Метка);
КонецЕсли;
Ждать = Истина;
Окончание = ТекущаяУниверсальнаяДата() + МаксимумСекунд;
Пока Ждать И ТекущаяУниверсальнаяДата() < Окончание
И Таймер.Состояние = СостояниеФоновогоЗадания.Активно Цикл
Таймер = Таймер.ОжидатьЗавершенияВыполнения(1); // точка останова здесь
КонецЦикла;
Если Вспомогательное И Таймер.Состояние = СостояниеФоновогоЗадания.Активно Тогда
Таймер.Отменить();
КонецЕсли;
КонецПроцедуры
// Фоновое задание, которое ждёт само себя с таймаутом, просто спит.
Процедура Пауза(Секунд) Экспорт
ТекущееЗадание = ПолучитьТекущийСеансИнформационнойБазы().ПолучитьФоновоеЗадание();
Если ТекущееЗадание <> Неопределено Тогда
ТекущееЗадание.ОжидатьЗавершенияВыполнения(Секунд);
КонецЕсли;
КонецПроцедуры
// Запуск экспортной процедуры серверного общего модуля одной функцией:
// ВФоне = Ложь - в текущем сеансе, точки останова работают без автоподключения;
// ВФоне = Истина - фоновым заданием, как её выполняет планировщик.
// Возвращает идентификатор фонового задания или Неопределено.
Функция ВыполнитьДляОтладки(ИмяМетода, ПараметрыМетода = Неопределено, ВФоне = Ложь, СОжиданием = Ложь) Экспорт
Если Не ПравоДоступа("Администрирование", Метаданные) Тогда
ВызватьИсключение "Запуск для отладки доступен только администратору";
КонецЕсли;
ПроверитьИмяМетода(ИмяМетода);
Аргументы = ?(ПараметрыМетода = Неопределено, Новый Массив, ПараметрыМетода);
Если Не ВФоне Тогда
ВызватьМетод(ИмяМетода, Аргументы);
Возврат Неопределено;
КонецЕсли;
ПараметрыЗадания = Новый Массив;
ПараметрыЗадания.Добавить(ИмяМетода);
ПараметрыЗадания.Добавить(Аргументы);
ПараметрыЗадания.Добавить(СОжиданием);
Задание = ФоновыеЗадания.Выполнить("ОтладкаНаСервере.ВыполнитьВФоне", ПараметрыЗадания, ,
"Отладка: " + ИмяМетода);
Возврат Задание.УникальныйИдентификатор;
КонецФункции
// Обработчик фонового задания, которое запускает ВыполнитьДляОтладки.
Процедура ВыполнитьВФоне(ИмяМетода, Аргументы, СОжиданием) Экспорт
Если СОжиданием Тогда
ЖдатьОтладчик(ИмяМетода, 120, Истина);
КонецЕсли;
ВызватьМетод(ИмяМетода, Аргументы);
КонецПроцедуры
// Итог фонового запуска: состояние или подробный текст ошибки.
Функция ИтогЗадания(Идентификатор) Экспорт
Задание = ФоновыеЗадания.НайтиПоУникальномуИдентификатору(Идентификатор);
Если Задание = Неопределено Тогда
Возврат "Задание не найдено";
ИначеЕсли Задание.ИнформацияОбОшибке <> Неопределено Тогда
Возврат ПодробноеПредставлениеОшибки(Задание.ИнформацияОбОшибке);
КонецЕсли;
Возврат Строка(Задание.Состояние);
КонецФункции
Функция ОжиданиеВключено(Метка)
Срок = ХранилищеОбщихНастроек.Загрузить("ОтладкаНаСервере", Метка);
Возврат ТипЗнч(Срок) = Тип("Дата") И Срок > ТекущаяУниверсальнаяДата();
КонецФункции
Процедура ВызватьМетод(ИмяМетода, Аргументы)
ЗаписьЖурналаРегистрации("ОтладкаНаСервере.Запуск", УровеньЖурналаРегистрации.Информация, , ,
ИмяМетода + ": " + ОписаниеСеанса());
Выражения = Новый Массив;
Для Индекс = 0 По Аргументы.ВГраница() Цикл
Выражения.Добавить("Аргументы[" + XMLСтрока(Индекс) + "]");
КонецЦикла;
// Выполнить() видит локальные переменные, поэтому значения не подставляются в текст
Выполнить(ИмяМетода + "(" + СтрСоединить(Выражения, ", ") + ");");
КонецПроцедуры
// Защита Выполнить(): только ИмяМодуля.ИмяПроцедуры серверного неглобального модуля.
Процедура ПроверитьИмяМетода(ИмяМетода)
Части = СтрРазделить(ИмяМетода, ".");
Модуль = Неопределено;
Если Части.Количество() = 2 И ЭтоИдентификатор(Части[1]) Тогда
Модуль = Метаданные.ОбщиеМодули.Найти(Части[0]);
КонецЕсли;
Если Модуль = Неопределено Или Не Модуль.Сервер Или Модуль.Глобальный Тогда
ВызватьИсключение СтрШаблон("""%1"" - не метод серверного общего модуля", ИмяМетода);
КонецЕсли;
КонецПроцедуры
Функция ЭтоИдентификатор(Имя)
Если ПустаяСтрока(Имя) Или СтрНайти("0123456789", Лев(Имя, 1)) > 0 Тогда
Возврат Ложь;
КонецЕсли;
Для Позиция = 1 По СтрДлина(Имя) Цикл
Символ = Сред(Имя, Позиция, 1);
Если Символ <> "_" И СтрНайти("0123456789", Символ) = 0 И ВРег(Символ) = НРег(Символ) Тогда
Возврат Ложь;
КонецЕсли;
КонецЦикла;
Возврат Истина;
КонецФункции
Пауза.Выполнить() принимает только метод серверного неглобального модуля и только от администратора.Встраивание — одна строка в начале метода задания или обработчика сервиса:
// Общий модуль ОбменССайтомСервер (флажок «Сервер»): метод регламентного задания.
// Ожидание включают на полчаса для пользователя, указанного в задании:
// ОтладкаНаСервере.ВключитьОжидание("ВыгрузкаЗаказов", "Регламент", 30)
Процедура ВыгрузитьЗаказы() Экспорт
ОтладкаНаСервере.ЖдатьОтладчик("ВыгрузкаЗаказов");
ЗаписьЖурналаРегистрации("Обмен.ВыгрузкаЗаказов", УровеньЖурналаРегистрации.Информация, , ,
"Старт: " + ОтладкаНаСервере.ОписаниеСеанса());
// ... прикладной код выгрузки
КонецПроцедуры
// Модуль HTTP-сервиса Заказы: тот же приём для запроса, который присылает сайт.
Функция ЗаказыPOST(Запрос)
ОтладкаНаСервере.ЖдатьОтладчик("HTTP.Заказы", 60);
Ответ = Новый HTTPСервисОтвет(200);
Ответ.УстановитьТелоИзСтроки("{""status"": ""ok""}", КодировкаТекста.UTF8);
Возврат Ответ;
КонецФункции
Сайт может оборвать запрос по таймауту раньше, чем вы подключитесь, — увеличьте таймаут или повторите запрос через curl. Если у задания не указан пользователь, флаг ставить некому: запускайте метод из обработки администратора.
// Внешняя обработка администратора, модуль формы: команда запускает метод
// регламентного задания фоном с паузой до подключения отладчика.
&НаКлиенте
Процедура ЗапуститьВФоне(Команда)
Идентификатор = ЗапуститьНаСервере("ОбменССайтомСервер.ВыгрузитьЗаказы");
ПоказатьОповещениеПользователя("Задание запущено", , "Подключите отладчик: " + Строка(Идентификатор));
КонецПроцедуры
&НаСервереБезКонтекста
Функция ЗапуститьНаСервере(ИмяМетода)
Возврат ОтладкаНаСервере.ВыполнитьДляОтладки(ИмяМетода, , Истина, Истина);
КонецФункции
-debug (TCP), а конфигуратор по HTTP, или наоборот.-debugServerPort.Нет: агент читает ключи только при старте. Если окно не согласовать, поднимите второй агент на других портах с -debug и отлаживайте копию базы.
Технически да, но любой с доступом к конфигуратору базы сможет остановить сеансы пользователей, а остановка внутри транзакции держит блокировки. Если иначе никак — HTTP, пароль -debugServerPwd и порт 1550 только для разработчиков.
Ключом --debug=http или --debug=tcp. Порт сервера отладки задаёт --debug-port (по умолчанию 1550), пароль — --debug-password.
EDT отлаживает только по HTTP, а сервер запущен с одним -debug, то есть по TCP. Добавьте -http и перезапустите службу.
Если ошибка есть только на рабочем сервере, перезапуск с -debug надо согласовывать, а причина прячется в обмене или фоновом задании, поиск растягивается на дни. Разместите задачу с текстом ошибки и шагами воспроизведения: оценка бесплатная, ответ в течение рабочего дня. Если база не падает, а тормозит, — услуга «1С тормозит».
Станьте частью сообщества!
Войдите или зарегистрируйтесь, и вы сможете участвовать в обсуждениях.