2017-01-05 8 views
0

Согласно git documentation посту-получить крюк по существу блокирует репо, пока не будет завершен:мерзавец после приема крючка не работает в фоновом режиме

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

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

Предположим, что у вас нет абсолютно никакой возможности разместить сценарий на сервере git для выполнения в виде команды оболочки с помощью всего подхода nohup /usr/bin/env python /path/to/post_receive.py 2>&1 > /dev/null &, аналогичного this question.

Давайте также предположим, что вы испробовали весь двойной os.fork() «ИНГ процесса демона, похожий на this и несколько других вопросов (нерабочего примера кода ниже) и обнаружил, что мерзавец еще ждет продолжительного ребенок до завершения крюка.

pid = os.fork() 
if pid == 0: 
    os.setsid() 
    pid = os.fork() 
    if pid == 0: 
     long_running_post_receive_function() 
    else: 
     os._exit(0) 
else: 
    for fd in range(0, 3): 
     os.close(fd) 
    os._exit(0) 

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

EDIT

работает минимальной структуры, без обработки исключений ... благодаря @torek и @jthill

pid = os.fork() 
if pid == 0: 
    os.setsid() 
    pid = os.fork() 
    if pid == 0: 
     for fd in range(0, 3): 
      os.close(fd) 
     long_running_post_receive_function() 
    else: 
     os._exit(0) 
else: 
    sys.exit() 
+0

Вы также можете использовать какую-то модель производителя/потребителя, в которой хук после приема отправляет какое-то «асинхронное сообщение» (которое может быть таким же простым, как касание файла), что приводит к тому, что потребительский демон заметьте это и выполните свою работу. – Mort

+0

Я, конечно, согласен с тем, что это альтернатива, которая действительно побеждает цель того, что я пытаюсь выполнить. –

+1

Я устал, но мне кажется, что вы делаете свой dup2() не в том месте. Fd все еще открыты в длительном процессе. – jthill

ответ

2

Вы должны закрыть все доступы дескрипторов, так что SSH знает он никогда не получит больше данных. Другими словами, вызов os.close на дескрипторы от 0 до 2. На практике вы должны те быть открытым, хотя, так что лучше, чтобы открыть os.devnull и os.dup2 полученный дескриптор через 0, 1 и 2 (по-настоящему надежным программным убедитесь os.open уже не возвращает значение 0 <= fd <= 2, конечно, если это так, то все в порядке, просто держите его на месте, пока вы оставите остальные).

(Вам по-прежнему нужен обычный трюк с двумя вилками, и может быть разумным отбросить идентификаторы сеанса и т. Д. В некоторых системах, основанных на Unix, есть библиотека под названием daemon, которая может быть в libc или libutil , который делает все это для вас. Некоторые детали неизбежно зависят от ОС, например, как отказаться от управляющего терминала, если таковые имеются. Однако главное, что отсутствует в вашем связанном с Python ответе, это замена stdin/stdout/stderr.)

+0

, если я не сделал ошибку или не оставил что-то, это все еще не работает. Я отредактировал свой вопрос с образцом того, что я пробовал. –

+0

рабочая минимальная структура добавлена ​​... спасибо! –