اجرای کدهای python در لینوکس با استفاده از systemd
اجرای کدهای python در لینوکس با استفاده از systemd

صوت مساله بسیار ساده‌ست، ما کد pythonمون رو نوشتیم، تست کردیم، حالا می‌خوایم بذاریمش یک گوشه به شکل دائم اجرا شه.
حداقل خواستمون اینه که:

  1. موقع روشن شدن سیستم کد به شکل خودکار اجرا شه
  2. اگر در هر صورت خطایی رخ داد که باعث کرش کردن برنامه شد به شکل خودکار کدمون مجددا راه اندازی شده

در بین همه‌ی گزینه‌های ممکن برای انجام این کار systemd راحت‌ترین و سرراست ترین راه رسیدن به خواسته‌های بالاست و کیه که ندونه من چقدر تنبلی رو دوست دارم!

ایجاد یک برنامه‌ی نمونه:

اول یک برنامه ساده درست کنیم که صرفا یک متن رو در یک حلقه‌ی بینهایت هر یک دقیقه یک بار در انتهای یک فایل اضافه کنه:

1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/python
from time import sleep

if __name__ == "__main__":
    n = 0
    while True:
        n += 1
        with open("/dos/codes/systemd_demo.txt", "a") as file:
            # get further user input/do stuff here
            file.write(f"{n} mississippi\n")
        sleep(1)

این برنامه رو به اسم systemd_demo.py ذخیره می‌کنیم.

اگر کد برنامه رو اجرا کنیم یک فایل به اسم systemd_demo.txt ایجاد خواهد شد:

systemd tail

دقت کنید که برای اجرای این کد از آدرس کامل محیط آناکوندام و آدرس فایلم استفاده کردم، در مرحله‌ی بعد به این آدرس کامل احتیاج داریم.

هشدار:. حتما یک بار توی ترمینال آدرس کامل رو بزنید و برنامه رو اجرا کنید، به خاطر ساختار import کردن ماژول‌ها و … در python ممکنه کد شما وقتی این شکلی اونو فرا می‌خونی با مشکل مواجه شه.

ایجاد فایل service:

با ویرایشگر دلخواهتون یک فایل با اسم مورد نظر خودتون (که مرتبط با اسم برنامه‌ای شما باشه) در آدرس /lib/systemd/system/ و با پسوند service. ایجاد کنید.

من از ویرایشگر nano استفاده می‌کنم، اگر nano رو نصب دارید کافیه در دستور زیر جای YOUR_SERVICE_NAME اسم مورد نظر خودتون رو بذارید.

 

sudo nano /lib/systemd/system/YOUR_SERVICE_NAME.service

 

ساختار کلی‌ای که برای ایجاد یک service لازم داریم به شکل زیره:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[Unit]
Description=YOUR SERVICE DESCRIPTION FOR HUMANS
After=multi-user.target
Conflicts=[email protected]

[Service]
Type=simple
ExecStart=YOUR PYTHON CODE EXECUTE COMMAND
StandardInput=tty-force
RemainAfterExit=yes
Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target

در ساختار بالا:

  • بجای YOUR SERVICE DESCRIPTION FOR HUMANS توضیحات مرتبط با اینکه این کد/سرویس چی هست رو می‌نویسیم.
  • بجای YOUR PYTHON CODE EXECUTE COMMAND دستور اجرای فایل خودمون وارد می‌کنیم.
  • اگر می‌خوایم بعد از اتمام حلقه‌ی اصلی برنامه python اون service فعال بمونه مقدار RemainAfterExit رو برابر yes قرار می‌دیم.
  • همچنین پارامتر RestartSec مقدار تاخیر هنگام اجرای مجدد کدمون رو مشخص می‌کنه.

ساختار فایل بالا رو من برای انجام برنامه‌ی مثال این پست به شکل زیر ویرایش کردم:

systemd demo service-1

فعال سازی و اجرای service:

هر بار که ما در آدرس /lib/systemd/system/ فایلی می‌سازیم و یا در اون فایل‌ها تغییری ایجاد می‌کنیم نیازه تا systemctl رو راه اندازی مجدد کنیم تا تغییراتمون اعمال بشن، این کار با دستور زیر انجام می‌شه:

 

sudo systemctl daemon-reload

  حال با دستورات زیر می‌تونیم serviceای که ایجاد کردیم رو مدیریت کنیم:

1
2
3
4
5
6
7
8
9
10
11
#To enable running service
sudo systemctl enable YOUR_SERVICE_NAME.service

#To stop running service
sudo systemctl stop YOUR_SERVICE_NAME.service

#To start running service
sudo systemctl start YOUR_SERVICE_NAME.service

#To restart running service
sudo systemctl restart YOUR_SERVICE_NAME.service

اگر همه‌چیز به خوبی پیش رفته باشه چنین خروجی‌ای خواهید دید و دیتا شروع می‌کنه وارد فایل systemd_demo.txt شدن.

sysemd status

منابع:

Auto-recovery of crashed services with systemd
How To Setup Autorun a Python Script Using Systemd
Writing a systemd Service in Python
https://stackoverflow.com/questions/44136655/why-standardinput-tty-in-oneshot-systemd-unit-files