Заметки

Управление вторым монитором из консоли

У меня стоят два монитора. Второй нужен во время встреч в Zoom или при совместной игре с друзьями (в обеих случаях туда удобно вывести камеры собеседников). Есть ещё несколько примеров, когда он полезен, но часто устройство просто простаивает. Чтобы не отвлекало, решил его выключать.

В чем тут засада: средствами ОС управлять вторым монитором неудобно (несколько кликов, скроллить надо, да ещё всё время путаю, куда лезть — в «Параметры экрана» или «Персонализацию»). Хотелось бы одной командой, а команду — на хоткей. И в идеале из скрипта всем этим рулить.

Скрипта я не нашел, но накопал готовую утилиту — MultiMonitorTool. Бесплатная. Под десятой виндой работает без проблем. Команды ниже включают-выключают 2-й монитор:

MultiMonitorTool.exe /disable 2
MultiMonitorTool.exe /enable 2  
MultiMonitorTool.exe /switch 2

Почему-то при включении монитора через enable или switch он иногда неверно позиционируется (например, до выключения он был справа, а после включения встал слева). Это поправимо. Сначала запишем конфигурацию в тот момент, когда включены оба монитора:

MultiMonitorTool.exe /SaveConfig Monitors.cfg

А потом, когда нужно включить монитор — загрузим сохранённый конфиг:

MultiMonitorTool.exe /LoadConfig Monitors.cfg

Утилита ещё много чего умеет (например, одна из команд перекидывает окна приложений между мониторами). Описание — по ссылке выше.

16 октября 2021 рабочее место

Самые большие зарплаты

Есть путь до CSV-файла, надо его открыть, прочитать заголовок (первая строка), найти колонку Salary и вывести топ 10 зарплат.

Ссылка

Вбросил свои пять копеек просто для полноты картины. Если забить на стабильность, читаемость и производительность — можно усечь где-то вдвое. Тут с самого начала было очевидно, что на баше выйдет короче, а на питоне проще — так что просто написал как привык.

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

В целом история напомнила хобби Евгения Степанищева — писать вывод американской «песни о пиве» на всех языках подряд. Задача с чтением CSV, кстати, мне тоже кажется скорее фаном — слишком узкий кейс, чтобы на его базе что-то всерьёз сравнивать.

Из смешного: у пары коллег язык 1С вызвал настолько острые проблемы со зрением, что они сочли нужным об этом сообщить :-) Отчасти понимаю желание самоутвердиться на стереотипе «1С — это плохо, понятненько?», но тут момент явно выбран неудачно. Предпочтения в синтаксисе — дело вкуса, а кроме них решение на 1С никак не отличается от решений на любом другом языке, где нет встроенной библиотеки для парсинга CSV.

2 октября 2021

Сборка этого сайта на GitHub

Последний год этот сайт работал на простой связке: статика, гитхаб и свой домен. То есть все страницы были заранее сгенерированы и лежали в репе гитхаба, к которой был подключен GitHub Pages.

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

Эта схема, в общем, неплохо работала, но меня раздражало количество кликов. Здесь скрипт дерни, там скрипт дерни, потом ещё с гитом повозиться надо. Хотелось бы попроще.

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

  1. Репозиторий исходных данных. Сюда я положил контент сайта: те самые текстовые файлы и чуть-чуть метаданных (заголовки страниц, даты их создания, теги для заметок и так далее).
  2. Репозиторий скрипта для генерации статики. Кроме самого скрипта, сюда я засунул разные ассеты (иконки, стили, манифесты — в общем, всё, что не нужно каждый раз генерировать, а можно просто «положить» рядом с получившимися html-ками).

Потом я накатал экшен, который просыпается при каждом пуше в репу с исходными данными. Вкратце, его логика:

  1. Клонировать репу со статикой и репу с генератором;
  2. Обновить репу со статикой с помощью генератора;
  3. Запушить изменения репы со статикой в мейн;
  4. Написать хозяину (мне) в телегу.

Вуаля! Теперь при любом изменении репозитория с исходными данными гитхаб немедленно (ну, как немедленно — в пределах минуты) обновляет репозиторий с готовым сайтом и деплоит его оттуда через GitHub Pages. Бонусом — веб-интерфейс для правки страниц сайта (собственно, сайт гитхаба). Почти чистый No Code :-)

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

29 сентября 2021 блог готово

Diablo

Хороший выпуск айтишного подкаста «Мы обречены» про выгорание разработчиков. Особых откровений нет, но что-то полезное для себя подчерпнуть можно. Очень понравилась аналогия с видеоиграми где-то ближе к середине:

Была такая игра — Diablo. Бегаешь ты там, RPG, всякие спеллы. У персонажа есть мана и здоровье, и когда у тебя маны на каст… Ха, звучу как задрот! Ну ладно. В общем, когда у тебя маны на каст не хватает, она у тебя начинает из здоровья браться.

— Доктор Кот

22 сентября 2021 работа видеоигры

Про молоток и гвозди

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

Вот есть у вас документ, да? В нём — несколько табличных частей. В каждой — поле для комментария. Делаете вы для этого документа печатную форму; если хотя бы в одной строке любой ТЧ есть комментарий — нужно использовать один шаблон, если комментариев нет — другой.

Задача примитивная, все мы миллион раз такое делали — ну, смотрим в выборку строк, натравливаем ПустаяСтрока() на нужное поле и грузим подходящий шаблон. Готово, можно пить кофе!

Однако, вместо короткого цикла я увидел это:

Ну то есть да, делаем матрешку из подзапросов, в самом нижнем из которых роемся в ТЧ (которые мы, напомню, только что выгребали для вывода на печатную форму). Ищем в них комментарии, если есть — ставим единичку. Нет? Нолик. Итог несколько раз группируем и возвращаем в скрипт.

Я сейчас даже не про нагрузку на СУБД (рискну предположить, что заметного эффекта этот трюк не дает — в конце концов, после отбора по ссылке выборка будет копеечной). Просто… Ну… Чекнуть выборку строк — пять строк кода. Понятных, простых, коротких, Сонару ругнуться негде. Как можно было родить вот это? Из большой любви к запросам?

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

15 сентября 2021 работа код с запашком

Без комментариев

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

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

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

8 сентября 2021 код с запашком

Медленное оповещение

Прочитал этот твит и внезапно вспомнил случай из практики. Прилетает запрос от клиента — мол, 1С тормозит, сделайте что-нибудь. Уточняем: тормозит всё-таки не вся 1С, а конкретная операция.

База клиента — переписанная УТ, проблемная операция — из блока доработок. Внутри — множество многоэтажных запросов, возня с таблицами значений, какие-то невнятные вычисления и пачка серверных процедур по семьсот строк каждая. Копию базы снять нельзя, ТЖ недоступен, доступ к СУБД закрыт, доступ к счётчикам — тоже. Отладка на сервере 1С выключена, включить — не вариант.

Бардак, в общем. Как понять, где тут всё вязнет? Ладно, конфигурацию можно менять — уже неплохо. Вешаю на операцию замер: ну да, думает над чем-то пару минут. Отлично! Потираю ручки и сужаю область поиска: докидываю целый ворох замеров на самые подозрительные участки.

Результат любопытный: тормозов нет! Код не то чтобы летает, но о минутах и речи нет — с учетом сложности, расходы в пределах допустимого. Может, какая-то сериализация данных между клиентом и сервером? Тщательно выверяю код серверной процедуры — нет, никакой трансляции. Всё, что было на сервере, осталось на сервере.

Перехожу к клиентской части. Что тут может тормозить-то?.. Выглядел код, упрощая, как-то так:

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

Я знатно офигел, полез проверять и в конце концов наткнулся на форму, которая ловила событие выполнение операции и подрывалась обновлять свои динамические списки. Запрос в одном из них и давал тормоза (там подзапрос к подзапросу к подзапросу и ворох соединений «через точку» — в общем, дальше не интересно).

Такая вот яломиште :-) Оповещайте с осторожностью!

18 августа 2021 работа оптимизация

Умер Павел Чистов

Павел Чистов в пятницу вечером умер из-за сердечной недостаточности. Если вы не знаете, кто это — вот некролог. Впрочем, раз вы читаете этот блог — скорее всего, знаете.

Никита Грызлов, Илья Леонтьев и Сергей Горшенин собирают деньги для помощи семье Павла. Кроме того, номер карты его вдовы есть в конце некролога по ссылке выше.

Берегите себя, пожалуйста.

1 августа 2021

Поиск долгих запросов с помощью Python

Выложил скрипт на Python для поиска длительных запросов в ТЖ 1С. Накатал его в приступе отчаяния: никак не мог понять, почему мой верный баш для одного из запросов выдаёт среднее время выполнения больше максимального.

Как выяснилось, проблема была в gawk. Для некоторых событий ТЖ эта утилита не могла определить длительность: пыталась преобразовать строку в число, фейлилась и… Нет, что вы! Конечно, не кидалась исключением! Просто невозмутимо считала эти строки за ноль и ехала дальше.

Патч, кстати, вышел ещё глупее проблемы: я просто сделал явное преобразование строки в число, и всё заработало как надо. Чем, блин, явное преобразование в мире gawk'а отличается от неявного? И, главное, почему?

Короче, цирк уехал, новый скрипт остался. Впрочем, он бережнее расходует память и процессор: в скрипте на баше для расчёта количества выполнений запроса, суммарного времени выполнения и максимального времени одного выполнения я использовал три коллекции, у каждой из которых ключом был текст запроса и его контекст. Соответственно, все три нужно было обновлять и держать в памяти.

Это вполне рабочая тактика, пока входящий поток не переваливает за сотни тысяч элементов: где-то тут мы начинаем терять гигабайты ОЗУ на хранении коллекций и прорву времени процессора на поиске в них. Новый скрипт попрямее: коллекция одна, но хранит всe данные по каждому запросу.

18 июля 2021 bash Python

Почему не баш?

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

Чтобы не быть голословным, давайте пример из практики. Есть, скажем, порядка семидесяти гигабайт логов ТЖ 1С, по которым нужно построить топ пояснений к исключениям — от самых частотных к менее частотным.

Плёвое дело, верно? Выгребаем EXCP, извлекаем Descr, считаем повторения. Даже нужный скрипт я как-то уже писал. Запускаю, терпеливо жду…

Знаете, сколько понадобилось времени? Я тоже нет: после того, как скрипт проработал сутки, я его вырубил и полез разбираться, в чём проблема. Затык возник где-то в скрипте gawk'а: именно она активно нагружала процессор (если не считать cat'а, которая время от времени читала очередную порцию данных).

Процессы

Беда, беда, огорчение! В общем, я подумал и переписал этот скрипт на Питоне. Новая версия отработала за 15 минут и дала мне:

  1. Топ пояснений по событиям исключений;
  2. Скрипт, который можно прочитать через полгода без помощи гугла;
  3. Уверенность, что я могу добавить в скрипт два-три условия и не вызвать Сатану случайным сочетанием операторов и ключей.

Конечно, я мог оптимизировать версию на баше. Вероятно, тормозит поиск в массиве — время, необходимое для поиска пояснения в массиве уже зафиксированных пояснений, линейно растет с увеличением размера массива. Можно, например, попробовать изменить подход к сбору данных — gawk'ом только извлекать сами пояснения, а результат сбора передать в тандем sort & uniq.

Однако это уже отчётливо отдаёт мемасом про буханку хлеба: из неё, конечно, можно сделать троллейбус, просто не очень понятно — зачем? Камон, мне бы проблему решить. А Питон с ней уже справился на твердую пятёрку, чем сэкономил мне кучу времени и нервов.

Собственно, к этому я вел. Родовые травмы баша понятны и нередко приемлемы, плюсы — приятны и очевидны, но при работе с ним вопрос иногда встает так: cтоит ли только ради того, чтобы получить решение именно на баше, потратить часа два на возню с утилитами, параметрами, мануалами и постами на Stack Overflow?

Вот поэтому не баш, да.

3 июля 2021 bash Python

Почему баш?

Периодически вижу вопросы коллег: а что, 1С всё ещё носится с башем, да? А чё не питон-то? Или павершелл, на худой конец? Вот чудаки!

Да, баш не родной для Windows (которая, напротив, родная для 1С) и притащить его туда — отдельная история; да, при усложнении задачи читаемость скрипта падает по экспоненте; да, с некоторыми задачами баш просто не справляется.

Однако главный плюс баша в том, что для многих задач по анализу ТЖ 1С он — самое простое и быстрое решение. Как старая отвертка, которой ещё дед пользовался. Она всегда под рукой — пусть поцарапанная, с зазубринами и слегка корявая, но всё еще прекрасно работает.

Пример? Допустим, нужно выгрести из ТЖ исключения; простоты ради договоримся, что достаточно первой строки каждого события. Получим примерно такой скрипт на питоне.

Скажете, его можно легко сократить вдвое? А то и втрое. В конце концов, мы решаем локальную задачу. Возня с читаемостью и предсказуемостью тут ни к чему.

Согласен! Но давайте сначала решим ту же задачу на баше:

grep -r --include "*.log" ',EXCP,' > result.txt

Вот почему баш.

23 июня 2021 bash Python

Метаданные не найдены

Метаданные не найдены

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

Во-вторых, нужно сделать так: выключить историю данных для объекта метаданных, а потом грохнуть накопленные версии объектов до того, как новые изменения объекта перекочуют из буфера в основную таблицу.

В двух словах о том, как вообще работает история данных. По дефолту она выключена, и достаточно привилегированный пользователь может включить её для нужных ему объектов — констант, справочников, документов и так далее. После этого при изменении данных в этих объектах платформа будет фиксировать, что именно меняется. Делает она это в два этапа: сначала — относительно быстрая запись в промежуточный буфер (таблицу _DataHistoryQueue0); потом, при вызове метода ОбновитьИсторию(), информация мигрирует в основное хранилище версий (таблицу _DataHistoryVersions) и становится доступна в интерфейсе приложения.

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

Для наглядности — рабочий код, воспроизводящий проблему для справочника Items на платформе 8.3.17.1989. Можете подставить любой другой объект, с которым работает история данных — разницы нет.

Как избежать этой ошибки? Ну, очевидно: метод ОбновитьИсторию() нужно вызывать непосредственно перед тем, как отключать историю для объекта. Лучше всего делать это в период, когда пользователи с системой не работают: есть риск, что между обновлением истории и её выключением вклинятся чьи-то транзакции, которые спровоцируют ту же проблему. Для гарантии можно использовать монопольный режим.

Ещё в голову приходит исключительная блокировка на таблицу объекта, но документация не советует вызывать метод ОбновитьИсторию() внутри транзакций — так что тут я не уверен.

Как исправить эту ошибку? Включите историю данных для проблемного объекта, обновите историю и выключите её обратно. Выйдите, так сказать, из класса и зайдите нормально.

8 июня 2021

Скрипт для синхронизации c NAS

Выложил на GitHub скрипт на Python, который я использую для синхронизации файлов между своим компьютером и домашним NAS'ом. У меня стоит Synology DS220j; с ним так-то идет целый вагон софта и в том числе утилита, которая умеет гонять файлы туда-сюда по расписанию. Однако сделана она, похоже, чисто для галочки: программа принялась глючить ещё на этапе настройки, после чего доверие к ней я потерял.

В общем, какое-то время я помучался с решениями конкурентов и в итоге вернулся к привычному rclone, с которым было всего две проблемы. Во-первых, нельзя нормально соединиться с SMB-шарой: да, логин и пароль можно сохранить в Windows и rclone будет их использовать, но они будут слетать при каждом удобном случае. Я вышел из положения, подключив шару как внешний диск.

Во-вторых, файлов и папок для синхронизации у меня оказалось много: директория здесь, директория там, конфиг оттуда, профиль отсюда… Чтобы не плодить лапшу, я накатал простой скрипт, который берет из конфига источники и приемники, а потом для каждого вызывает rclone по одному и тому же шаблону.

7 июня 2021 готово Python рабочее место

Как готовиться к 1С:Эксперту

В середине мая я сдал экзамен на статус эксперта в 1С по технологическим вопросам крупных внедрений. Подготовка вышла долгая, почти два года — так что я чертовски рад, что наконец-то справился.

В сети есть море материала про этот экзамен и связанные с ним темы — начиная с курса Виктора Богачева и заканчивая, не знаю, релевантным чатом в Телеграме. То есть вопрос из заголовка заметки обычно не стоит. Но я хочу написать о паре психологических заморочек, к которым лучше быть готовым заранее и о которых обычно не вспоминают.

Нехватка дофамина

Этот экзамен — сложный. Подготовка может затянуться, как и сдача: очень вероятно, что потребуется несколько попыток. Я справился со второго раза, но у людей выходит по-всякому — среди моих знакомых есть те, кто сдал с третьего, пятого или даже восьмого захода.

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

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

Например, я для отвлечения катал скрипты для домашней автоматизации — генератор статики для этого сайта, органайзер на текстовых файлах, обвязку для домашнего NAS'а и тому подобные штуки, до которых раньше никак руки не доходили. Подойдут любые задачи — включая те, что с айтишечкой вообще не связаны. Почистить слив в ванной? Отличная идея!

Нехватка памяти

Если вы не работаете с проблемами производительности 1С каждый день, этот экзамен — очень ресурсоемкий контекст. Вы будете держать в голове массу вспомогательных данных, которые обычно берете из документации: флаги трассировки и имена динамических представлений Microsoft SQL Server, настройки PostgreSQL и рекомендации по их заполнению, перечень стандартных индексов платформы и так далее, и тому подобное. Во-о-от такенная куча информации! (показывает руками, какая)

Между тем, наш мозг при работе с большими объёмами данных порой крепко напоминает СУБД, работающую с переполненным буферным кэшем. Другими словами: всё, что не нужно в данный момент, будет выгружено из памяти. Готовьтесь забывать самые неожиданные вещи: номер своей квартиры, кличку соседской собаки, день рождения жены — и это ещё не самые диковатые последствия. Я, пока готовился, чуствовал сильное духовное родство с Джонни Мнемоником — персонажем старого-престарого киберпанка, который загрузил себе в мозги столько данных, что чуть не отбросил коньки :-)

Не надо так

Выхода тут мне видится два, оба довольно очевидные.

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

Во-вторых — старайтесь строить ассоциативные цепочки для наиболее заковыристых штук. Взять, например, баш! Название утилиты sed проще запомнить, если знать, что это сокращение от Stream EDitor. Утилита cat называется так, потому что concatenate, а не потому что кошка, но если вам проще запомнить второй вариант — так и делайте. Почему нет?

Или, скажем, маркер последовательности байтов. \xef\xbb\xbf, ага. Его я намертво запомнил — только не смейтесь — через абсолютно иррелевантную фразу «Elf Friend BB Best Fight». Понятия не имею, почему моя голова работает через такую жо такие заковыристые интерфейсы, но жаловаться я не собираюсь. Главное — отыскать их!

25 мая 2021 готово

Новый скрипт поиска долгих запросов

Обновил скрипт поиска долгих запросов в технологическом журнале платформы. Ранняя версия содержала серьёзный косяк: она старательно группировала DBMSSQL по Sql и Content, но игнорировала случаи, в которых поле Sql отсутствовало (для DBMSSQL это не то чтобы норма, но встречается).

Ну и код слегка причесал, чтобы два раза не вставать: добавил разметку и комментарии, а часть логики gawk'а вынес из основного тела в функции. Да, скрипт стал смотреться длиннее, чем он есть на самом деле, зато читать его стало куда проще.

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

26 апреля 2021 bash готово

Пучок скриптов

Выложил на GitHub ещё несколько скриптов для разбора технологического журнала платформы, которые написал за последнее время:

  • Частотные события. Группирует события по наименованию, считает количество воспроизведений для каждого и выводит в порядке убывания — от наиболее частотного к наименее частотному. Практического применения у этого скрипта, скорее, нет; просто фиксировал для себя, какой процесс кластера какие события пишет.
  • Описания исключений. Группирует EXCP по полю Name; для каждого наименования выводит варианты значений поля Description, которые были у исключений с таким наименованием. С помощью этого скрипта можно составить примерную картину: какие исключения действительно проблема, а какие — просто белый шум, который можно игнорировать и, например, закинуть в фильтры Кибаны.
  • Блокировки по ID соединения и области. Удобен для поиска виновника таймаута на управляемых блокировках: скрипт выгребает из ТЖ все TLOCK'и по конкретной области от конкретного соединения, а потом выстраивает их в хронологическом порядке.

24 апреля 2021 bash готово

SKUUUID в своем глазу

Пару недель назад Александр Кунташов у себя на канале запостил забавный скрин перечисления из Библиотеки Электронных Документов, создателей которого откровенно манили длинные аббревиатуры. Я бодро острил на тему родства ИППДОИПУПДУКД'а и московского ГНУВНИВИПФИТ'а, а потом увидел в собственном коде вот эту красотку:

SKUUUID

Ещё не вполне рука маэстро, конечно, но движение определенно в том же направлении. Вспомнилась притча про сучок в чужом глазу и суковатое бревно — в своём :-)

22 февраля 2021 код с запашком

Проблема с литералом даты при пересчете итогов

Итак, в ходе рутинного пересчета итогов из Конфигуратора мы неожиданно получили ошибку «номер года в литерале типа дата превышает 3999». Это значит, где-то в базе есть (или пытается появиться) дата больше, чем предельно допустимая с точки зрения 1С (31.12.3999 23:59:59).

Исключение

Ладно, что с этим делать?

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

Другой, более методологически правильный подход — настроить сбор ТЖ (SDBL, EXCP и EXCPCNTX) и получить примерно такой лог. Ищем в нём событие EXCP (исключение), а непосредственно перед ним — событие SDBL (SQL-запрос в терминах платформы). Этот запрос — причина сбоя; в его тексте видим имя нужной нам таблицы (AccumRgTn11530). Имя объекта конфигурации для неё можно вытащить любой обработкой, построенной на методе ПолучитьСтруктуруХраненияБазыДанных().

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

Например, у меня был случай, когда после исправления движений записи с некорректными датами сохранялись в таблице оборотов. Средствами платформы их удалить было нельзя, но размер базы позволял играться с реструктуризацией. Я выкинул следующий финт: отключил признак «Использование в итогах» для всех измерений регистра и применил изменения; потом вернул признак на место и пересчитал итоги. В итоге таблица оборотов регистра была физически удалена, а потом создана и наполнена заново — уже без дат на много веков вперёд.

В крайнем случае можно было удалить проблемные записи с помощью прямых SQL-запросов (DELETE или даже TRUNCATE). Но это, во-первых, нарушает лицензионное соглашение с разработчиками платформы, а во вторых — опасно (по неосторожности можно удалить что-то важное и не заметить). Так что не советую, э-э, повторять в домашних условиях :-)

6 февраля 2021

Определение видимости объекта

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

Так вот, помню, лет пять назад я искал способ понять из кода — видит пользователь объект или нет? Чисто с точки зрения функциональных опций. Тогда я почему-то не нашел решения, а ведь оно до смешного простое; вот, например, функция ровно для этого. Логика:

  1. Перебираем опции и ищем объект в составе каждой из них.
  2. Если объект есть в составе опции, проверяем: опция активна? Если да — значит, пользователь видит объект.
  3. Если объект не включен ни в одну опцию — тоже видит.

Конечно, результаты такого анализа как минимум нужно кэшировать (хотя бы из-за запроса в цикле), но в остальном он вполне адекватен. Никак не возьму в толк, почему я тогда не написал что-то похожее? Ох, надеюсь, спустя следующие пять лет мои нынешние занозы в заднице тоже будут отлетать на раз-два-три.

17 января 2021

Рекурсивный поиск по файлам

Время назад я примеривался к поискам уязвимостей в коде скриптами на bash (звучит грозно, но это просто рекурсивный поиск текста с помощью регулярных выражений). Скрипты-то я тогда написал, но, как сегодня понял — несколько… Ректально, кхм. Для решения хватает одного egrep! То есть из связки find, xargs и egrep можно выкинуть два компонента из трех.

Например, сегодня у нас возникла проблема: конфигурация перестала собираться в последнем релизе EDT. Подозрение пало на битые GUID — ссылки на объекты метаданных, удаленные из конфигурации. Платформа не всегда справляется с их вычисткой после того, как удалит сами объекты; я уже пару раз писал про это (например, здесь или вот тут).

В общем, мы решили порыться в выгрузке конфигурации — найти GUID'ы и оценить, все ли они находятся там, где положено. Общее решение — одна-единственная команда:

egrep -rn '.{8}-.{4}-.{4}-.{4}-.{12}' dump

Ключ r включает рекурсивный поиск, ключ n — заставляет утилиту пристегнуть к найденной строке не только имя файла, в котором найдена строка, но и номер самой строки. Последний параметр, dump — имя директории, где нужно искать.

Регулярку можно сделать точнее, но и такой за глаза хватает. Что до ложных срабатываний (то есть GUID, которые не являются битыми ссылками) — их легко отсеять через пайп. Например, скрипт ниже не будет выводить строки с GUID, в которых есть подстрока «uuid»:

egrep -rn '.{8}-.{4}-.{4}-.{4}-.{12}' dump | grep -v 'uuid'

14 января 2021 bash

Ранее Ctrl + ↓