<?php // Полная загрузка сервисных книжек, создан 2024-01-05 12:44:55
global $wpdb2;
global $failure;
global $file_hist;
///// echo '<H2><b>Старт загрузки</b></H2><br>';
$failure=FALSE;
//подключаемся к базе
$wpdb2 = include_once 'connection.php'; ; // подключаемся к MySQL
// если не удалось подключиться, и нужно оборвать PHP с сообщением об этой ошибке
if (!empty($wpdb2->error))
{
///// echo '<H2><b>Ошибка подключения к БД, завершение.</b></H2><br>';
$failure=TRUE;
wp_die( $wpdb2->error );
}
$m_size_file=0;
$m_mtime_file=0;
$m_comment='';
/////проверка существования файлов выгрузки из 1С
////файл выгрузки сервисных книжек
$file_hist = ABSPATH.'/_1c_alfa_exchange/AA_hist.csv';
if (!file_exists($file_hist))
{
///// echo '<H2><b>Файл обмена с сервисными книжками не существует.</b></H2><br>';
$m_comment='Файл обмена с сервисными книжками не существует';
$failure=TRUE;
}
/////инициируем таблицу лога
/////если не существует файла то возврат и ничего не делаем
if ($failure){
///включает защиту от SQL инъекций и данные можно передавать как есть, например: $_GET['foo']
///// echo '<H2><b>Попытка вставить запись в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>$m_comment));
wp_die();
///// echo '<H2><b>Возврат в начало.</b></H2><br>';
return $failure;
}
/////проверка лога загрузки, что бы не загружать тоже самое
$masiv_data_file=stat($file_hist); ////передаем в массив свойство файла
$m_size_file=$masiv_data_file[7]; ////получаем размер файла
$m_mtime_file=$masiv_data_file[9]; ////получаем дату модификации файла
////создаем запрос на получение последней удачной загрузки
////выбираем по штампу времени создания (редактирования) файла загрузки AA_hist.csv, $m_mtime_file
///// echo '<H2><b>Размер файла: '.$m_size_file.'</b></H2><br>';
///// echo '<H2><b>Штамп времени файла: '.$m_mtime_file.'</b></H2><br>';
///// echo '<H2><b>Формирование запроса на выборку из лога</b></H2><br>';
////препарируем запрос
$text_zaprosa=$wpdb2->prepare("SELECT * FROM `vin_logs` WHERE `last_mtime_upload` = %s", $m_mtime_file);
$results=$wpdb2->get_results($text_zaprosa);
if ($results)
{ foreach ( $results as $r)
{
////если штамп времени и размер файла совпадают, возврат
if (($r->last_mtime_upload==$m_mtime_file) && ($r->last_size_upload==$m_size_file))
{////echo '<H2><b>Возврат в начало, т.к. найдена запись в логе.</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>'Загрузка отменена, новых данных нет, т.к. найдена запись в логе.'));
wp_die();
return $failure;
}
}
}
////если данные новые, пишем в лог запись о начале загрузки
/////echo '<H2><b>Попытка вставить запись о начале загрузки в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>0, 'last_size_upload'=>$m_size_file, 'comment'=>'Начало загрузки'));
////очищаем таблицу
$clear_tbl_zap=$wpdb2->prepare("TRUNCATE TABLE %s", 'vin_history');
$clear_tbl_zap_repl=str_replace("'","`",$clear_tbl_zap);
$results=$wpdb2->query($clear_tbl_zap_repl);
///// echo '<H2><b>Очистка таблицы сервисных книжек</b></H2><br>';
if (empty($results))
{
///// echo '<H2><b>Ошибка очистки таблицы книжек, завершение.</b></H2><br>';
//// если очистка не удалась, возврат
$failure=TRUE;
wp_die();
return $failure;
}
////загружаем данные
$table='vin_history'; // Имя таблицы для импорта
//$file_hist Имя CSV файла, откуда берется информация // (путь от корня web-сервера)
$delim=';'; // Разделитель полей в CSV файле
$enclosed='"'; // Кавычки для содержимого полей
$escaped='\
Просто и элегантно!
А почему бы не сделать проверку на наличие дублирования перед записью нового объекта?
(1) Andris_infostart, конечно, можно сделать проверку
Решение интересное, возьму на заметку.
(1) Насколько я понимаю, задача ставилась не допустить параллельного запуска этой обработки.
Определить же в процессе работы обработки, что создается дублирующий объект или «так и должно быть» в общем случае затруднительно. Да к тому же требует дополнительных усилий 🙂
(6) 7OH, У меня такой вариант не взлетел. Я его пробовал.
Вот кстати чего мне не хватает. так это «второй стороны» к объекту Блокировка. Нечто вроде расширенного Заблокирован(), чтобы возвращало, кем, когда и откуда.
можно добавить константу типа булево, и проверять ее перед запуском механизма обработки:)
Попытка Исключение ?
Может лучше
?
(9) ezhikofff, работа через константу подразумевает ручную корректировку при аварийном завершении работы программы с работающей обработкой. Мое решение работает полностью автоматически.
(10) я не настаиваю, просто предложил.
(5) ediks, вариант про блокировку для повторного запуски обработки хорош, но вопрос в топике был следующим:
«В результате, возникает нежелательное дублирование. Как этого можно избежать?» ©
Поэтому проверка на дубли, по моему мнению, будет уместнее (в контексте поставленного вопроса), даже если запустят в 2 и более раз эту обработку.
По теме получается, что вопрос задан»как избежать дублирования?», а по факту приведён пример того, как запретить повторный запуск обработки, которая может наделать дублей.
(10) Можно добиться некого полуавтомата, если употребить не константу, а запись некого регистра, при запуске обработки создавать, на выходе удалять, записывать дату (и время) начала блокировки и на старте проверять не просто наличие такой записи, но и дату — скажем, считать вчерашнюю запись уже неактуальной. Для обработок, которые достаточно редко запускаются, должно хватить. (8) Кстати, в регистре можно записать и кто, и откуда, и даже зачем.
(13) gaglo,
А я бы не стал без нужды плодить сущности. Есть простая проблема и автор предложил простое решение. Если проблема сложнее то и решение нужно более сложное.
(7) Это странно. Попытка -> Исключение это как-то не очень кошерно. Но все равно спасибо за идею.
У моих бухов такое возникает не иногда, а каждый день. Почти 🙂
(6) Собственно в помощи все описано. Выделил жирным шрифтом ключевое предложение.
Заблокирован()
Возвращаемое значение:
Тип: Булево.
Истина — элемент заблокирован; Ложь — в противном случае.
Описание:
Определяет, заблокирован ли элемент данным объектом.
Доступность:
Сервер, толстый клиент, внешнее соединение.
Примечание:
Следует учитывать, что этот метод используется для проверки блокировки объекта базы данных конкретным объектом встроенного языка. Он не может быть использован для проверки, заблокирован ли вообще объект базы данных, например, другими пользователями.
Показать
(11) ezhikofff, константа это первый приходящий на ум вариант 🙂 Я ответил, чтобы показать возможные проблемы данного пути
(12) Andris_infostart, согласен, что проверка дублей хороший вариант. Надо смотреть каждый случай. В моем случае проверка приведет к дополнительным одиночным запросам.А с помощью запрета на одновременный запуск обработки я полностью исключу вероятность ошибки.
Уточните, пож-ста, как вызвать обработку «перед открытием»
(19) Эта блокировка вызывается непосредственно в форме обработки в событии формы «ПередОткрытием».
И сколько по времени держится блокировка? Если не ошибаюсь, есть ограничение по времени и оно не большое.
Лучше создайте отдельный справочник Блокировки (Наименование, КтоЗаблокировал, КогдаЗаблокировал)
В менеджере справочника надо вставить функцию ЗаблокироватьДействие(Название)
Эта функция возвращает Пустой элемент справочника в случае успешной блокировки или возвращает ссылку на элемент справочника при неудаче.
Из этой ссылки можно будет получить инфу Кто и Когда заблокировал это действие.
И еще одну фунцию Разблокировать(Название)
В функции передается название действия, которое надо заблокировать.
Такая реализация позволит реализовать механизм блокировок для неограниченного числа действий/обработок,
а также не придется создавать левых элементов в других справочниках, что ну крайне неверно и некрасиво.
(22) VZhulanov, если блокировать надо много чего, то можно и справочник создать. Если обработка одна, то зачем так заморачиваться?
Не проще использовать существующие объекты конфигурации? Например в типовых есть или справочник, или регистр «Сохраненные настройки». Туда, на мой взгляд, и следует записывать «блокировочную» запись. Это помимо очевидного «ЗначениеВФайл». А корежить типовые — увольте
(24) the1,
1. А причем здесь «ЗначениеВФайл»?
2. В конфигуратор можно вообще не лезть. Блокировать можно любой объект. Предопределенные значения нужны в основном для распределенных конфигураций. А в локальной базе блокировать можно любой понравившийся объект.
(25) автор предлагает создать предопределенный элемент справочника. Научите делать это без конфигуратора?
(25)
При нажатии на кнопку «Создать документы»
Показать
В 1С 7.7. я для таких целей просто использовал внешний файл.
Тоже не надо лезть в конфигурацию или блокировать существующие объекты.
Чтобы заблокировать создавал и открывал файл.
Чтобы разблокировать — удалял файл.
Если файл не удаляется, значит обработка запущена другим юзером.
(27)
а если зависнет чего, то в файла так и останется Истина
Блокировка хороша тем, что снимется автоматом
(26) the1, добавил ответ в текст статьи
(21) allegrosoft, У меня блокировка держалась больше часа. Дольше не проверял, но явных ограничений в документации 1С не видел.
Хорошее решение, почти полный аналог с клюшечным вариантом отлова активных пользователей.
Все идеи с клюшек в снеговик кочуют помаленьку.. реинкарнация в новом виде.
🙂
(26) В 8.3.3 Для объектов конфигурации, которые могут содержать предопределенные данные, реализовано свойство ИмяПредопределенныхДанных. Заполнив это свойство у существующего объекта (или у вновь созданного) Вы получите предопределенный элемент, созданный без конфигуратора.
Блокировки одновременного запуска нескольких экземпляров обработки возникают не только при загрузке данных. Есть множество регламентных процедур (в частности, проведение по партиям), множественный запуск которых может приводить к взаимным блокировкам…
В этом смысле создание справочника «Блокировки» хорошая идея. В справочнике создают запись под каждую Монополизируемую обработку и постоянно обновлять отметку о срабатывании «МонопольнойОбработки». Ведь, простая блокировка не является панацеей от зависания… В случае, если сеанс организовавший блокировку зависнет, то блокировка будет оставаться, а основной сеанс обработки не работать!
Соответственно, есть смысл при старте не только проверять Факт блокировки, но и анализировать кем и когда заблокировано, а в случае обновления отметки о срабатывании МонопольнойОбработки, можно диагностировать критические зависания первичного сеанса… Соответственно можно вычислить зависшие сеансы и призвать Администратора для решения проблем.
классная штука, спс.
согласен с Andris_infostart, проверять перед записью и нет проблем.
А надо ли разблокировать выбранный элемент при закрытии обработки, или блокировка при закрытии снимется автоматом?
(37) ronhard, Блокировка снимется автоматом
Имхо, решение не совсем верное.
Справочник Номенклатура или любой другой — не предназначены для подобной операции. Это неверное архитектурное решение. Если с вашими базами будут работать другие программисты, они не поймут назначение этого костыля и запросто его удалят.
Кроме того, использовать предопрделенные элементы в типовых объектах это уж точно не верно. Вы предлагаете универсальное решение, а оно в таком случае должно учитывать все способы поддержки. Наверное, глупо будет снимать конфу с полной поддержки, включать возможность изменения типового справочника ради одновременной работы одной единственной внешней обработки.
Без острой необходимости лучше не менять типовые объекты!
Хочется чего-то нового — добавляйте новые объекты в новых подсистемах.
Находить по коду/наименованию тоже не совсем верно. Код и наименования объектов могут измениться, элементы могут быть так же удалены.
Ну и главное — такая разработка не решает основной проблемы — исключения дублирования работы.
Да, второй пользователь увидит, что обработка кем-то уже запущена. Но он так же увидит, что она не запущена, когда откроет её спустя 10секунд после того, как первый её уже закрыл. И запустит выгрузку в сом-базу, да.
Да и время жизни блокировки в данном случае не коррелирует с периодичностью выполняемого функционала. Пользователь может открыть обработку и уйти
в запойпить чай до пятницы.Если хотите красивых универсальных решений — используйте объекты, которые более информативно отображают состояние выполняемых работ. Есть возможность — добавляйте новые объекты — константы, справочники, регистры сведений. Нет возможности — используйте типовые объекты, предназначенные для хранения информационных сведений.
А лучше вообще использовать Журнал регистрации, записывать в него время выполнения, результат. И при открытии обработки анализировать и выводить эти записи пользователю, чтобы он видел, что, к примеру, выгрузка была проведена Ивановым 10 секунд назад с положительным результатом.
(39) Stim213, ключевое слово «одновременно». Журнал регистрации для этого не нужен.
(13) gaglo, конечно правильнее использовать регистр сведении, к примеру с одним измерением «имя обработки», при запуске делать запись в регистр, а при закрытии обработки вычищать его. Ну а на случай аварийного завершения программы надо бы при первом запуске программы тоже его чистить.
Проверка использования обработки без изменений конфигурации.
(Для последних версий конфигураций основанных на БСП.)
(за исключением кода самой обработки)
1) Включаем в «Общих настройках» флаг «Дополнительные реквизиты и сведения»
2) Заходим в пункт «Дополнительные сведения»
см.рис. Начало_настроек_блокировки.png
3) Добавляем для «Пользователя» новые дополнительные сведения с типом значения булево.
см.рис. Доп_свойство_блокировка.png
см.рис. Список_доп_свойств_блокировок.png
Теперь в нашем распоряжении типовой регистр сведений «ДополнительныеСведения»
и элементы типового Плана вида харакетристик «ДополнительныеРеквизитыИСведения»
(в данном случае Блокировка обработки №1 и Блокировка обработки №2)
В регистр сведений «ДополнительныеСведения» мы независимо можем записывать записи по полям:
Объект — Пользователь
Свойство — Элемент плана вида характеристик.
Значение — Булево
см.рис. Рег_ДополнительныеСведения.png
4) Осталось только нужную нам обработку «научить» (дописать код)
работать с типовым регистром сведений «ДополнительныеСведения»
На предмет анализа и формирование соответствующих записей.
И программно в коде обработки назначить ей соответствующий элемент плана видов характеристик.
(Код писать не буду. и так все «разжевал» :))
ИТОГ:
Получаем подобный механизм контроля, с минимальными изменениями типовых механизмов и объектов метаданных.
И можем не только мониторить на предмет блокировки, но и смотреть кто и какую обработку использует в текущий момент.
А почему нельзя воспользоваться механизмом управляемых блокировок?
(43) -fox-, блокировок чего? объектов? Так они могут блокироваться как угодно, в том числе с помощью управляемых блокировок. При запуске двух загрузок или двух потоков создания документов может не происходить пересечений на конкретном объекте.
Для всех, кого интересует получение блокирующего пользователя, я дополнил статью. Все делается одной строкой кода, без создания регистров сведений 🙂
Вообще, в данной статье я предложил конкретное решение конкретной, очень узкой задачи. При рассмотрении похожих задач, но с другими начальными условиями, возможно использование других решений. Они не лучше и не хуже. Все зависит от деталей. В моем случае, это решение было наименее трудозатратным в создании и поддержке. И я не вижу смысла обсуждать в комментариях альтернативные варианты, которые можно использовать в похожих задачах.
Пишите статьи о своих вариантах, приводите ссылки и будьте счастливы 🙂
(44)
Создается спр. (Если будет несколько обработок) или константа и их блокируешь.
На сколько я понял, у тебя тоже самое, но использован спр. «Номенклатура» и специально для этого созданный элемент «ЭлементДляБлокировкиОбработки».
ИМХО лучше не засорять спр. заведомо не используемой информацией.