Асинхронность в управляемом интерфейсе 1С




Принцип обмена данными из 1С с сайтом (на MySQL) и выдачи (публикации) этих данных по запросу.
PHP-Скрипт автоматической загрузки данных из файла данных в формате CSV в базу данных сайта работающего на WordPress.

В продолжение моей темы: 1С:Альфа-Авто Автосалон Автосервис: обмен с сайтом.
С помощью данного скрипта можно загружать в автоматическом режиме, по расписанию, данные сервисных книжек (ремонтов авто) из 1С:Альфа-Авто Автосалон Автосервис.
Также можно загружать данные в ручном режиме: для этого делается скрытая страница, где размещается специальная кнопка.
Комментарии размещенные внутри скрипта разъяснят логику и порядок действия.
Комментарии с "/////    echo" использовались для отладки.
Дополнительно создана таблица для журналирования результатов загрузки данных.
Скрипт включает в себя защиту от SQL инъекций (думаю безопасность соблюдена в полной мере).
В кратце:
1. Пишется скрипт, который запускает этот.
2. Создается регламентное задание в WordPress, по которому запускается скрипт из п.1. 
3. Этот скрипт осуществляет проверку на существование файла обмена в папке.
4. Если данные не новые, загрузка не производится.
5. Если данные новые, очищается таблица сервисных книжек.
6. Загружаются новые данные.

Собственно сам скрипт:

<?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='\

29 Comments

  1. FreeArcher

    Большое спасибо за статью. Долго думал над этой асинхронностью, зачем да почему… А тут все ответы.

    Reply
  2. TokAdm

    Статья очень полезная. Автору спасибо, за то , что разложил «по полочкам» вопросы асинхронного кода.

    Reply
  3. webester

    Фиксин наконец то смог понять, что такое запрет модальных окон и решил написать по этому поводу статью?

    Reply
  4. Gureev

    На сайте ИТС написано, имхо, намного понятнее.

    Reply
  5. fixin

    (4) не скажи, видел я тот ИТС

    (3) когда человек говорит мне про «запрет модальных окон», я смеюсь и отвечаю «блокировка всего интерфейса».

    Reply
  6. ineshyk

    Это не модное явление, а вынужденные меры для нормальной работы веб клиента.

    Reply
  7. webester

    (5)

    когда человек говорит мне про «запрет модальных окон», я смеюсь и отвечаю «блокировка всего интерфейса».

    Да хоть горшком назови. Суть не меняется. Разработчики это называют именно использованием или не использованием «Режима модальных окон».

    не скажи, видел я тот ИТС

    И что не устроило? Очень подробное описание, когда использовать, когда не использовать, для чего это нужно, примеры по типовым ситуациям гораздо более информативные, чем здесь, разобраны разные случаи.

    Reply
  8. vipetrov2

    Асинхронность нужна не для клиент-серверной архитектуры, а для распаралеливания вычислений. Потому что «ВыполнитьДлительнуюОперацию(ВыполнитьДлительнуюОперациюЗавершение)» и «ВыполнитьДлительнуюОперациюЗавершение()» будут запускаться на стороне сервера, при чем здесь клиент? И вообще 1С это один большой костыль для программиста. Просто разработчики платформы внедряют различные шаблоны проектирования, но при этом получают большие накладные расходы, на свои новшества. И при этом, как кто сгладить негативный эффект они и не собираются. Им вообще ни чего не стоить создать синхронные и асинхронные версии функций. Так нет, например, на стороне клиента с файлами можно работать только асинхронно.

    Можно благодаря этой асинхронности сделать индикатор статуса процесса, но опять же за счет слишком трудоемкого процесса обмена между клиент — сервером эта примочка удлинит выполнение на 10-20%.

    Reply
  9. kiv1c

    (5) а подскажите ссылку на ИТС пожалуйста

    Reply
  10. Bukaska

    (9) Может это? http://its.1c.ru/docs/v8nonmodal/

    Reply
  11. fixin

    (7) важно неиназвание, а суть. Без модальных окон нельзя

    .(8) асинхронность можно было сделать прозрачно для программиста 1с на уровне платформы, но платформописатели 1с любят превращать си в ассемблер, излишне напрягая программиста.

    Reply
  12. fixin

    (6) их можно было бы спрятать от программиста в реализации. Незачем программиста нагружать ассемблером

    Reply
  13. starik-2005

    Не хочу придираться к автору, т.к. это, понятное дело, штука бессмысленная. Да и к статье не хочу придираться. Одно понятно — автор вообще не вкурил, что такое асинхронность в контексте «новомодных веяний и в 1С тоже» ))).

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

    Но с точки зрения это самой «новомодности», асинхронность — это отсутствие прямой последовательности между командами. Т.е. есть у тебя вопрос пользователю. Синхронность — это когда ты открываешь пользователю диалог с вопросом и ждешь ответа, как соловей лета. Т.е. команды дальше не выполняются, ждется ответ, после которого уже можно посмотреть, что же это самое модальное окно нам вернуло и, соответственно, обработать результат.

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

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

    Никаких претензий к автору — как уж понял, так и слава Богу.

    Reply
  14. fixin

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

    Так что это еще вопрос кто читал и не понял и понял не так. 😉

    Reply
  15. tailer2

    В отличиЕ от типовой

    но это так, придирки

    а по существу что-то мне здесь не нравится

    вот код из управляемой формы

    и что вы думаете?

    &НаКлиенте
    Процедура ПриОткрытии(Отказ)
    ScrptCtrl= Новый COMОбъект(«MSScriptControl.ScriptControl»);
    ScrptCtrl.Language=»vbscript»;
    // ждет, временный потребитель
    ScrptCtrl.AddCode(«Dim objService, objEventSource, objEvent, strResult
    |Set WinMGMT = GetObject(«»winmgmts:\.
    ootcimv2″»)
    |Set objEventSource = WinMGMT.ExecNotificationQuery («»SEL ECT * FR OM __InstanceCreationEvent WITHIN 2 WHERE TargetInstance ISA ‘Win32_Process’ AND TargetInstance.Name =’notepad.exe'»»)
    |Set objEvent = objEventSource.NextEvent
    |»);
    
    КонецПроцедуры
    

    Показать

    висит, цуко, намертво, пока блокнот не откроешь

    **

    поясню: если выполнить этот скрипт просто файлом из-под винды, винда продолжает работать, как бы и не ждет наступления события

    Reply
  16. starik-2005

    (14)

    Так что это еще вопрос кто читал и не понял и понял не так. 😉

    Ну так я и говорю, что асинхронность — это callback’и, а не фоновые задания, которые и раньше были. Тут Вам не надо ничего понимать — достаточно поверить, ибо попытки что-то Вам объяснить сами знаете чем кончатся — потом поймете.

    В компьютерном программировании, асинхронные событиями являются те, которые возникают независимо от основного потока выполнения программы. Асинхронные действия — действия, выполненные в неблокирующем режиме, что позволяет основному потоку программы продолжить обработку[6].

    Суть тут в том, что есть основной поток, который сгенерировал отображение диалога, при этом основной поток не ждет результата этого диалога, ибо результат обрабатывается в отдельной функции, указанной при открытии этого диалога. То же самое для начала чтения текстового файла, когда он читается независимо от основного потока программы, а после того, как он прочитался, вызывается callback-функция. В итоге нет блокировки ожидания в коде основной программы. Т.е. нет в асинхронном режиме «Результат = Длг.Выбрать()», а есть «Длг.Показать(CallBackFunction);» и продолжение выполнения кода после этого (или выход из процедуры — как будет угодно г-ну программисту). Вот это и есть асинхронность в том понимании, которое связано с «неблокирующим» основной поток выполнением.

    В общем не стоит путать фоновые задания, которые и в 8.0 вроде как были, с той «новомодной» асинхронностью, которая методологически убирает модальность. В вебе не так просто организовать ввод данных в диалог, чтобы дождаться результата — там как раз асинхронные механизмы используются. При вводе данных используются calback’и, и даже при рендеринге каждый кадр рассчитывается через вызов callback-функции, которая в конце каждого кадра дергается. Т.е. рендерим объект, отрабатываем логику (меняем состояние объектов на основании событий и поведения), вызываем callback-функцию для отрисовки следующего кадра, пьем чай…

    ЗЫ: Как пример предела асинхронности можно привести промисы. Вот это и есть тру-асинхронность, до которой 1С еще пилить и пилить (кстати, тут где-то про промисы в коментах к статье про последовательные асинхронные вызовы было, вот пруф).

    Reply
  17. spacecraft

    (15)

    висит, цуко, намертво, пока блокнот не откроешь

    Ну так использован синхронный метод же. Чего ожидали?

    Может переписать под асинхронный метод ExecNotificationQueryAsync?

    Reply
  18. tailer2

    (17) а ведь я утрудил себя и написал «поясню» :(((

    просто запустите этот файлик из-под винды, а потом откройте блокнот

    винда не зависнет 🙂

    Reply
  19. tailer2

    (17) на самом деле здесь помогает (ну, может помочь, не всем) понимание, как устроены «аппаратные» прерывания в компутере

    Reply
  20. spacecraft

    (18) это серьезно сравниваете?

    Тогда прямой путь к изучению что такое ОС и чем отличается от программ.

    При запуске любого приложения создается отдельный поток. Его еще называют основным потоком приложения.

    Reply
  21. tailer2

    если мне будут нужны советы, я спрошу

    Reply
  22. spacecraft

    (21) да я и не давал конкретно вам совет. Просто указал на глупость.

    Reply
  23. tailer2

    :))

    не дождешься

    Reply
  24. spacecraft

    для чистоты эксперимента:

    Запустить этот скрипт в интерпретаторе командной строки без ключевого слова Start.

    Потом уже сравнивать с 1С.

    Reply
  25. ineshyk

    (12) ну, смотря какого программиста.

    Программиста 1С незачем вообще нагружать разделением директив &НаКлиенте, &НаСервере.

    Программист 1С должен знать бух учет, зарплату и макросы писать. Такой себе, «продвинутый бухгалтер».

    Так было раньше, по крайней мере, до управляемого интерфейса.

    Reply
  26. ineshyk

    (8)Вы не правы. Асинхронность в 1С нужна чисто для того, чтобы нормально работать в браузере, так как движок JS’а по другому работать не умеет. И открыть просто-так модальное окно, и сказать всей клиентской среде — замри, в веб клиенте не получится.

    А работа длительных операций вообще никак не связана с асинхронностью: ни логически, ни физически.

    Reply
  27. starik-2005

    (26)

    И открыть просто-так модальное окно, и сказать всей клиентской среде — замри, в веб клиенте не получится.

    Гыгыгы…

    alert(‘Замрем…’);
    Reply
  28. luter-89

    А вопрос перед записью документа? Это ж самый сложный пример, почему не описан? Я изучал по ИТС

    Reply
  29. boln

    (12)

    их можно было бы спрятать от программиста в реализации.

    Если только в 9.0 🙂

    Перерабатывать компилятор восьмерки только ради этого уже никто не будет.

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *