#python-3.x #jenkins
#python-3.x #дженкинс
Вопрос:
На моем сервере Jenkins (версия 2.167) выполняется задание сборки оболочки, которое выполняет скрипт, написанный на Python 3.7.0.
Иногда пользователям необходимо отменить сборку вручную (нажав на красную кнопку с белым крестом в графическом интерфейсе Jenkins GUI), и скриптам Python необходимо обработать прерывание, чтобы выполнить задачи очистки перед завершением. Иногда прерывание обрабатывается правильно, но в других случаях кажется, что родительский процесс завершается до того, как скрипт Python сможет запустить процедуру очистки.
В начале скрипта Python я определил следующее:
def cleanup_after_int(signum, frame):
# some cleanup code here
sys.exit(0)
signal.signal(signal.SIGINT, cleanup_after_int)
signal.signal(signal.SIGTERM, cleanup_after_int)
# the rest of the script here
Достаточно ли кода, который я использую, или мне следует рассмотреть что-то еще?
Документ Дженкинса для прерывания сборки https://wiki.jenkins.io/display/JENKINS/Aborting a build
Нашел довольно хороший документ, показывающий, как это работает: https://gist.github.com/datagrok/dfe9604cb907523f4a2f
Комментарии:
1. Мое текущее решение использует задачу Post Build, ищет текст журнала «Прервано» и выполняет скрипт очистки.
2. Документ gist.github.com/datagrok/dfe9604cb907523f4a2f это отличный источник, и он помогает выяснить, как обрабатывать сигналы в коде.
Ответ №1:
Вы описываете гонку:
кажется, что родительский процесс [иногда] завершается до того, как скрипт Python сможет запустить процедуру очистки.
Было бы полезно узнать, откуда вы это знаете, с точки зрения симптомов, которые вы наблюдаете.
В любом случае опубликованный вами код python выглядит нормально. Все должно работать должным образом, если SIGTERM доставлен вашему процессу python. Возможно, дженкинс просто завершает родительский bash. Или, возможно, оба bash и python находятся в одной группе процессов, и дженкинс сигнализирует группе процессов. Обратите внимание на PGRP в ps -j
выводе.
Возможно, ваш код очистки сложен и требует ресурсов, которые не всегда доступны. Например, возможно, stdout
это канал к родительскому файлу, и код очистки регистрируется в этом открытом файловом дескрипторе, хотя иногда его закрыл мертвый родительский файл.
Вы могли бы сначала «демонизировать» код очистки, используя этот вызов из главы 3:http://man7.org/linux/man-pages/man3/daemon.3.html . Тогда ваша очистка, по крайней мере, была бы менее резкой, что привело бы к более воспроизводимым результатам при ее тестировании и использовании в рабочей среде.
Вы могли бы выбрать, чтобы родительский скрипт bash организовал очистку:
trap "python cleanup.py" SIGINT SIGTERM
python doit.py
Вы могли бы вообще не беспокоиться об очистке при выходе. Вместо этого запишите все, что вы испортили, и (синхронно) очистите это непосредственно перед запуском, затем запустите свой регулярно запланированный скрипт, который выполняет реальную работу. Предположим, вы создали три временных файла и хотите привести их в порядок. Добавьте каждое из их имен в /tmp/temp_files.txt
непосредственно перед созданием каждого из них. Обязательно очистите буферы и сохраните запись с помощью fsync()
или close()
.
Вместо ведения журнала вы могли бы выбрать очистку при запуске без ведения журнала. Например:
$ rm -f /tmp/{1,2,3}.txt
может быть достаточно. Если в прошлый раз были созданы только первые два, а третий не существует, ничего страшного. Используйте подстановочные знаки, где это уместно.