Русский
Русский
English
Статистика
Реклама

Shell scripting

Из песочницы Доверяй, но проверяй контроль неотправленных писем в Битриксе с уведомлением админу

09.07.2020 20:08:37 | Автор: admin

Предыстория


Когда-то у меня возникла необходимость проверять наличие неотправленных сообщений в 1С-Битрикс: Управление сайтом (далее Битрикс) и получать уведомления об этом. Проблемы с отправкой почты были крайне редкими, однако довольно неприятными событиями, т.к. обычно это были заказы, подтверждения регистрации и прочие важные письма.

Сложность была в том, что если используемый Битриксом метод отправки почты перестал работать(с большой вероятностью причина в этом), то этим же самым методом отправлять уведомление будет ненадёжно.

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

Задача


  1. Получить реквизиты для соединения с БД из конфига сайта Битрикса
  2. Соединиться с БД
  3. Проверить количество неотправленных писем
  4. Сравнить количество с предельно допустимым
  5. Принять решение об отправке уведомления


Реализация


На вход shell-скрипту будут поступать 3 параметра:

  1. Путь к конфигу сайта Битрикса (path_to_bxdb_config)
  2. Текст запроса к БД (single_num_value_query)
  3. Предельно допустимая величина (max_num_value)

Для корректной работы запрос к БД должен возвращать одиночное числовое значение.

Код скрипта check_bx_db_value.sh
#!/bin/bash## Site: https://github.com/AlexeyGogolev/check-bx-db-value#mysql="$(which mysql)" # получение пути к mysqlphp="$(which php)" # получение пути к phpdeclare -A CLParams # массив значений параметров КСdeclare -a CLParams_keys # массив ключей для массива параметров КСdeclare -A DBSettings # массив значений переменных конфигаdeclare -a DBSettings_keys # массив ключей для массива значений переменных конфигаDBSettings_keys=(DBLogin DBPassword DBName)CLParams_keys=(path_to_bxdb_config single_num_value_query max_num_value)param_num=0 # счетчик параметров КС# получение параметров КСfor key in "${CLParams_keys[@]}" ; do     ((param_num++))                     CLParams[$key]=${!param_num}    # ${!param_num} здесь генери-т $1 $2... done# если нет последнего параметра, показываем справкуif  [ -z "${CLParams[${CLParams_keys[$param_num-1]}]}" ] ; then    printf "Script compares result returned by <${CLParams_keys[1]}> to given <${CLParams_keys[2]}>.\nIf the result more than the given value, then exit with code 1, else exit 0.\n"    printf "Usage: \n\t$(basename ${BASH_SOURCE[0]}) " ; for key in "${CLParams_keys[@]}" ; do printf "<$key> "; done ; printf "\n"    printf "Example: \n\t$(basename ${BASH_SOURCE[0]}) \"/www/ab.cd/bitrix/php_interface/dbconn.php\" \"select count(id) from b_event where SUCCESS_EXEC<>'Y'\" 5\n"     exit 10fi# выход если конфиг пустой или его нет if ! [ -s "${CLParams[path_to_bxdb_config]}" ] ; then     printf "File ${CLParams[path_to_bxdb_config]} doesn't exist or empty.\n"    exit 20fi# выход если параметр запроса к БД содержит команду из "запретного списка"echo ${CLParams[single_num_value_query]} | grep -i -q -E 'delete|update|insert|drop' && printf "query \n${CLParams[single_num_value_query]}\nisn't allowed\n" && exit 30# получение значений переменных из php-config -n -- без php.ini , -r -- выполнить код без тэгов <?...?>for key in "${DBSettings_keys[@]}" ; do     DBSettings[$key]="$($php -n -r 'include("'${CLParams[path_to_bxdb_config]}'"); print $'$key';')"done# экспорт пароля mysql в переменную окружения (по соображениям безопасности)export MYSQL_PWD=${DBSettings[DBPassword]}# получение одиночного значения из БД: -N -- без названий колонок ; -B - (batch) - результаты без "бокса" вокруг значений; -e выполнить запросnum_value=`${mysql} -u ${DBSettings[DBLogin]} -N -B -e "use ${DBSettings[DBName]}; ${CLParams[single_num_value_query]}"`# отображение значенийecho "Result of the query (from DB ${DBSettings[DBName]}): ${num_value}, ${CLParams_keys[2]}: ${CLParams[max_num_value]}"# сравнение значенийif [ $num_value -gt ${CLParams[max_num_value]} ]; then    exit 1fi


Пример вызова скрипта
#!/bin/bashcheck_bx_db_value.sh \/www/ab.cd/bitrix/php_interface/dbconn.php \select count(id) from b_event where SUCCESS_EXEC<>'Y' \2



Проверка результатов выполнения с кодами завершения скрипта
запускаем:

$ ./ab_cd_unsent_check.sh && echo "success" || echo "failure"

получаем:

Result of the query (from DB ab_cd): 0, max_num_value: 2success

Добавим неотправленных сообщений и запустим снова.

$ ./ab_cd_unsent_check.sh && echo "success" || echo "failure"

а теперь:

Result of the query (from DB ab_cd): 4, max_num_value: 2failure


Все работает как нужно! В первом случае значение в БД не превышает заданного, скрипт выдает код 0 по завершении. Во втором значение в БД превышает заданное, скрипт завершается с кодом ошибки.

Настройка конфигурации monit


В данной статье я приведу пример конфигурации monit для отправки сообщений на e-mail.
Подразумевается, что на машине уже установлен и настроен monit.

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

Пример конфигурации monit
check program ab_cd_unsent_check with path /home/bitrix/scripts/ab_cd_unsent_check.shevery 2 cycles    group mailif status != 0 then alert

Файл конфигурации следует поместить в /etc/monit.d/.

Для упрощения демонстрации, в этом примере установлено 2 цикла (здесь 1 цикл = 30 сек).
Чтобы monit не отправлял ложные алерты, в реальных условиях, нужно ставить столько циклов, чтобы письма успевали уходить подбирается опытным путём. Здесь следует учитывать среднее количество сообщений, генерируемых сайтом, и скорость(время) их обработки почтовым сервером.

Для проверки работы конфигурации в терминале выполняем:
# systemctl restart monit# monit status

получаем:
Без неотправленных сообщений


С неотправленными сообщениями


Так выглядят уведомления от monit на почту:
Появились неотправленные сообщения!


Все сообщения отправлены (теперь всё норм.).


Отправка уведомлений из monit работает корректно.

Заключение


Надеюсь решение получилось достаточно универсальным и подойдёт для других задач.

Вот и всё! Исходники для статьи можно скачать здесь.

P.S. Кому не сложно прошу поделиться в комментариях возникают ли у вас подобные задачи?
Если да, то каким образом они решаются?
Подробнее..

Из песочницы Масштабирование CICD монорепозитория

19.07.2020 18:07:47 | Автор: admin

Lerna


Дано


  1. Монорепозиторий на базе Lerna и Yarn workspaces.
  2. Десяток приложений, и десятки общих пакетов на TypeScript, Angular, NodeJS.
  3. Высокое покрытие тестами самых разных мастей (модульные, интеграционные, e2e).
  4. и Atlassian Bamboo CI/CD.

Задача


Ускорить имеющиеся пайплайны в 2 раза (до, хотя бы, получаса). Попутно повысив стабильность до 90%.


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


Было



Для инкрементальной сборки lerna filter options:


lerna run build:packages --since --include-merged-tags --include-dependencies

Чтобы попасть в инкремент пакеты должны проходить фазу lerna publish в артифакторий (JFrog):


# Masterlerna publish patch --yes# Featurelerna publish prepatch --yes --no-push --preid "${PREID}"

При такой организации pipeline, возможно только вертикальное масштабирование путём увеличения мощностей elastic агентов.


Этот подход крайне ограничен. И с ростом числа пакетов средняя длительность постепенно росла (~1ч).


Надо заметить, что в силу короткого релизного цикла (сутки), стабильность JFrog и, как следствие, всего pipeline была низка (~70%).


Идея


Собирать каждое приложение независимо от остальных.
На входе монорепозиторий
На выходе production image приложения.


Тестировать тоже независимо от остальных.
На входе production image (зависимости устанвлены, все пакеты собраны)
На выходе отчеты о тестировании и покрытии.


Это позволит собирать и тестировать в параллельном режиме, масштабируясь горизонтально по мере развития линейки продуктов.


Но в таком случае размер node_modules составил бы ~1.5Gb (суммарные зависимости всех пакетов монорепозитория). Что негативно отразилось бы на размере image, времени его загрузки в AWS ECR, и времени развертывания.


Фокусировка


Чтобы "урезать" ("сфокусировать") монорепозиторий для сборки, тестирования и развертывания одного конкретного приложения, достаточно найти подмножество пакетов в общем графе пакетов и переписать декларацию workspaces в корневом package.json непосредственно перед сборкой на CI.


#!/usr/bin/env nodeconst { spawnSync } = require('child_process');const { existsSync, promises: { readFile, writeFile } } = require('fs');const { join, dirname, relative, normalize } = require('path');const PACK_JSON_PATH = './package.json';(async (apps) => {    const packJSON = JSON.parse((await readFile(PACK_JSON_PATH)).toString());    await spawnSync('yarn', ['global', 'add', 'lerna'], { shell: true });    const locations = await listPackages(apps);    const [someLocation] = locations;    const basePath = findBasePath(someLocation);    // All paths should be relative to monorepo root    const workspaces = locations.map((loc) => normalize(relative(basePath, loc)));    packJSON.workspaces.packages = workspaces;    const packJSONStr = JSON.stringify(packJSON, undefined, 2);    await writeFile(PACK_JSON_PATH, `${packJSONStr}\n`);})(    process.argv.slice(2),);async function listPackages(apps = []) {    const filterOptions = apps.flatMap((app) => ['--scope', app]);    const { stdout } = await spawnSync(        'lerna',        ['ls', '-pa', '--include-dependencies', ...filterOptions],        { shell: true },    );    return String(stdout).split(/[\r\n]+/).filter(Boolean);}function findBasePath(packageLocation) {    return existsSync(join(packageLocation, 'lerna.json'))        ? packageLocation        : findBasePath(dirname(packageLocation));}

После "фокусировки" все команды (в том числе и changed) будут относится лишь к подмножетсву пакетов конкретного приложения.


Размер node_modules удалось снизить в среднем в 3 раза.


Fixed mode


Lerna fixed mode, отказ от lerna publish и артифактория позволили повысить стабильность и упростить логику pipeline.


Но как же быть с инкрементальностью сборок?


Инкремент


Для инкремента достаточно отслеживать изменения через команду lerna changed


lerna changed -a --include-merged-tags

Если изменений не обнаружено, то можно переиспользовать latest image приложения для развертывания и тестирования:


#!/usr/bin/env bashAPP=$1lerna-focus.js "${APP}"function nothing_changed() {    [[ -z "$(lerna changed -a --include-merged-tags || true)" ]]}function pull_latest_image() {...}function push_latest_image() {...}function tag_latest_with_version() {...}pull_latest_imageif nothing_changed; then    tag_latest_with_version    exitfibuild-app.sh "${APP}"if is-master.sh; then    push_latest_imagefi

Стало



Что дальше?


Сейчас активно набирают обороты такие решения как Nx: Extensible Dev Tools for Monorepos. Это предмет следующих разборов.


Если эта статья окажется полезной, то в следующей расскажу о горизонтальном масштабировании "на коленке" модульных тестов (Angular, Jest, ElasticSearch, Bamboo CI).

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru