Асинхронные вызовы




Принцип обмена данными из 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='\

25 Comments

  1. jobkostya1c8

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

    Reply
  2. Князь

    Весьма полезно. За реализацию оповещения пользователя о ходе процесса выполнения серверных процедур отдельное спасибо.

    Reply
  3. LsrGroup

    В случае БСП лучше использовать подсистему ДлительныеОперации. Там все это уже реализовано.

    Reply
  4. webdimon

    Правильно я понимаю что данную схему можно будет реализовать в 8.2 и в 8.3, верно?

    Reply
  5. rtnm

    (5) webdimon, верно, зависимостей от платформы 8.3 нет (в демонстрационном примере есть — ПоказатьПредупреждение)

    Reply
  6. webdimon

    Хотел бы уточнить, к примеру, у меня есть некий рабочий стол на упр.формах., на котором информация обновляется каждые 30 секунд, получение данных для обновления занимает 5 секунд , и все это время , тоесть 5 секунд, пользователь не может работать так как форма висит.

    С вашим методом, как я понял, получиться этого избежать, верно?

    Reply
  7. rtnm

    (7) webdimon, новых методов я не изобретал, я лишь показал одну из возможных реализаций асинхронных вызов скрывающую детали. Любая такая реализация так или иначе все равно будет использовать один и тот же подход — фоновые задания. Я думаю, что моя реализация или любая другая, можешь вам помочь. Но проще проверить, чем строить догадки. Пробуйте, а потом расскажите о результате 🙂

    Reply
  8. pumbaE

    (4) LsrGroup, длительные операции — это одна из частностей асинхронного вызова, если у вас длительная операция прервется, то вы об этом вряд-ли узнаете и ваша важная задача не выполнится в полном объеме.

    Reply
  9. ybatiaev

    Весьма наглядная конфигурация. И конкретно в помощь прямо сейчас! Автору респект!!!

    Reply
  10. ybatiaev

    сделал асинхронную функцию ЗапускПриложения() . Работает. Но никак не могу разораться как отследить её состояние 🙁

    в самой функции делаю архивацию баз данных с командной строки

    Reply
  11. rtnm

    (11) ybatiaev, нужно сделать следующие вещи:

    1. в самой асинхронной функции/процедуре вызывать АсинхронныеВызовы.ОбновитьЗначениеХодаВыполнения и/или АсинхронныеВызовы.ДобавитьСообщениеХодаВыполнения

    2. в форме реализовать экспортную процедуру обработчик хода выполнения

    3. при запуске асинхронной функции/процедуры 3-им параметром передать ссылку на форму, а 5-ым имя обработчика хода выполнения

    P.S. у всех функций программного интерфейса (т.е. находящихся в модуле АсинхронныеВызовы) есть описания, так что думаю разберетесь

    Reply
  12. androgin

    (7) webdimon, тебе подойдут фоновые задания. они точно решат твою проблему.

    На примере загрузки курсов валют посмотри )

    Reply
  13. kozlovmv

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

    Возможно ли достичь действительно параллельного выполнения?

    Reply
  14. rtnm

    (14) kozlovmv, у вас клиент-серверный или файловый вариант базы?

    Reply
  15. 1C_Extentions

    На вебклиенте такие асинхронные вызовы не проканают ?

    Reply
  16. herfis

    (9) По сути реализации — практически одно и то же. В БСП тоже есть возможность подключить обработчик оповещения завершения задания. И суть его реализации точно такая же, как у ТС — через обработчик ожидания на клиенте.

    Из преимуществ разработки вижу только не завязанный на БСП, более стройный и лаконичный API. Если же БСП уже есть, то нет смысла плодить сущности.

    ЗЫ. Упс, не обратил внимание на дату комментария. С тех пор БСП существенно допиливалась. На тот момент этого функционала могло и не быть.

    Reply
  17. starik-2005

    Интересно, когда уже перестанут фоновое выполнение называть асинхронным? Да, оно, конечно, асинхронно, но т.к. callback-функцию приходится изображать с помощью обработчиков ожиданий, это не тру-асинхронность, которая подразумевается под самим этим понятием асинхронности. О как ))

    Reply
  18. baza1978

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

    Reply
  19. sorter1

    Добрый день коллеги

    Никто не реализовывал закрытие всех фоновых заданий перед закрытием системы?

    В том числе и зависших.

    Reply
  20. spezc

    (20) а что вы имеете ввиду под закрытием заданий? прерывание сессий? и перед каким закрытием системы — при любом случае, когда пользователь закрывает программу?

    Reply
  21. sorter1

    да. закрытие всех открытых фоновых заданий.

    в мобильном приложении — бывает зависает одно из заданий и грузит потом всю систему.

    Reply
  22. ybatiaev

    (20) Добрый день! Мы тоже боролись, боролись и пришли к выводу, что:

    1. отключение, какое реализовано в 1С, работает только в клиент-серверном варианте, в файловом не работает вообще;

    2. отключение в 1С 100% НЕ гарантирует прибитие сеансов. Не разобрались, но в консоли они видны. Скорее какой-то механизм стартуется на отключение;

    3. прибитие сеансов в консоли, тоже не всегда приводит к нужному результату, поскольку фоновые задания настроены на определённое количество раз перезапуска;

    4. Есть фоновые задания, которые запускаются вне описанных регламентных заданий со своим режимом перезапуска в случае аварийного завершения. Показалось, что индексируется данные порциями, т.е. даже если одна порция завершилась корректно, запускается следующая. Отключили полнотекстовый поиск и все, какие возможно, регламентные задания… пофигу… фоновые задания стартуются с завидным постоянством.

    Что в итоге. написали некое расширение, которое завершает работу пользователя ИЗ ПОД САМОГО ПОЛЬЗОВАТЕЛЯ. Т.е. как бы сам пользователь себя закрывает. Ну вот кроме DefUser…

    По крайней мере эта форма отключения корректнее, чем килять процессы в консоли.

    P.S.

    1. зависшие процессы не киляются;

    2. Если у пользователя открылось окно с вопросом и висит, то корректно сам себя этот юзер закрыть не может;

    3. Если у пользователя что-то выполняется, то закрытие произойдёт только после завершения выполнения какой-либо операции. Лучше, конечно, свои операции оборачивать в транзакцию.

    Короче ещё тоже думаем.

    Reply
  23. sorter1

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

    Reply
  24. Алеся777

    Добрый день! Можете дать обработку скачать. Срочно нужно.

    Reply
  25. Алеся777

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

    Reply

Leave a Comment

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