LaunchDaemon запускает другой экземпляр Python для терминала - PullRequest
0 голосов
/ 25 апреля 2020

С LaunchDaemon, имеющим следующий plist:

<?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
        <key>Label</key>
            <string>com.test.testing</string>
        <key>ProgramArguments</key>
            <array>
                <string>python3</string>
                <string>/Users/my-name/python-daemon/python_daemon_test.py</string>
            </array>
        <key>StandardErrorPath</key>
            <string>/var/log/test-Error.log</string>
        <key>StandardOutPath</key>
            <string>/var/log/test.log</string>
        <key>RunAtLoad</key>
            <true/>
    </dict>
    </plist>

, где сценарий, который должен быть запущен:

#!/usr/bin/env python3

import sys
print(sys.version)
print(sys.path)

У меня такое поведение, которое я не понимаю.

Когда я запускаю скрипт в терминале (где which python3 приводит к /Users/my-name/opt/anaconda3/bin/python3), я получаю следующий вывод:

3.7.4 (default, Aug 13 2019, 15:17:50)
[Clang 4.0.1 (tags/RELEASE_401/final)]
['/Users/my-name/python-daemon', '/Users/my-name/opt/anaconda3/lib/python37.zip', 
'/Users/my-name/opt/anaconda3/lib/python3.7', 
'/Users/my-name/opt/anaconda3/lib/python3.7/lib-dynload', 
'/Users/my-name/.local/lib/python3.7/site-packages', 
'/Users/my-name/opt/anaconda3/lib/python3.7/site-packages', 
'/Users/my-name/opt/anaconda3/lib/python3.7/site-packages/aeosa']

, который соответствует желаемому, поскольку фактический (не игрушка) ) скрипт, который я sh запускаю, использует пакет PyObj c, который я установил в Anaconda.

Однако, когда скрипт запускается LaunchDaemon, я получаю следующее в файле test.log :

3.7.3 (default, Mar  6 2020, 22:34:30) 
[Clang 11.0.3 (clang-1103.0.32.29)]
['/Users/my-name/python-daemon', 
'/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.7/lib/python37.zip', 
'/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7', 
'/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/lib-dynload', 
'/Applications/Xcode.app/Contents/Developer/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/site-packages']

Это проблема, поскольку фактический скрипт, который я хочу запустить sh, зависит от пакета в Anaconda. Я ожидал, что, поскольку первый аргумент программы в скрипте был python3, он будет работать с тем же python3, что и в терминале, но я ошибаюсь.

Почему скрипт ведет себя так? Я думал, что это может быть потому, что он запускает сценарии как sudo, но sudo which python3 также возвращает путь к Anaconda.

Как я могу решить эту проблему? Я уверен, что простым решением было бы просто установить нужный мне пакет где-нибудь в версии Xcode Python3. Тем не менее, я не совсем уверен, как это сделать. Также было бы немного неудовлетворительно, так как я хотел бы знать, почему LaunchDaemons ведут себя так.

1 Ответ

1 голос
/ 26 апреля 2020

Демоны запуска (и задания cron и ...) не работают в вашей обычной среде Terminal / shell, поэтому они не получают никаких настроек, надстроек и т. Д. c настроены в вашем Terminal / оболочка среды. В частности, они не запускают различные сценарии инициализации оболочки (~ / .bash_profile, ~ / .bashr c, et c), которые обычно содержат команды для настройки среды.

In В случае с c для anaconda его установщик добавляет раздел в файл ~ / .bashr c, чтобы добавить каталог с двоичными файлами anaconda в PATH и, возможно, множество других изменений. Это влияет на вашу среду ваших сеансов bash в терминале, но не действует для агентов запуска или даже сеансов терминала в других оболочках (zsh теперь используется по умолчанию, и это вызывает некоторые проблемы с этим ).

Для демона запуска я бы порекомендовал не запускать на нем скрипты установки оболочки - это ваша личная конфигурация, которая не имеет никакого реального бизнеса, выполняемого системным процессом. Вместо этого я бы создал короткий сценарий оболочки, который включает соответствующую настройку (скопированную из вашего ~ / .bashr c), и затем запускает ваш python сценарий. Затем измените Launch Daemon, чтобы он запускал этот сценарий, а не запускал сценарий python напрямую.

PS Поскольку сценарию не нужно ничего делать после запуска сценария python, это случай где сценарий может использовать команду exec для выхода из себя и запустить сценарий python вместо в том же процессе . Это означает, что python будет прямым подпроцессом launchd, и launchd может контролировать, контролировать и т.д. c так, как ему нравится. (Это в отличие от обычного запуска сценария python, и в этом случае у вас будет бесполезный процесс оболочки, ожидающий завершения сценария python до sh, чтобы он мог завершиться sh. )

Так что я бы закончил сценарий:

exec python3 /Users/my-name/python-daemon/python_daemon_test.py
...