2013-11-03 17 views
6

Tôi đang viết một tập lệnh Python 2.7.
Tóm lại, tập lệnh này được chạy mỗi tối trên Linux và kích hoạt một số quy trình.python - đảm bảo tập lệnh chỉ được kích hoạt khi

Tôi muốn đảm bảo tập lệnh này không chạy song song nhiều lần (về cơ bản cố bắt chước mô hình Singleton nhưng ở cấp ứng dụng).

Mã số Ví dụ

def main(): 
    # before doing anything, I'd like to know whether this 
    # script was activated and alive. 
    # if so, error out 

    # do something 

if __name__ == "__main__": 
    main() 

Đề xuất

Giải pháp ngây thơ sẽ là để tạo ra một số loại của một tập tin khóa, hoạt động như một mutex.
Điều đầu tiên chúng ta làm là kiểm tra xem tệp này có tồn tại không. nếu vậy, sau đó trường hợp khác của kịch bản đã tạo ra nó và chúng ta nên lỗi. khi tập lệnh được thực hiện, chúng tôi sẽ xóa tệp này.
Tôi giả định giải pháp này sẽ hoạt động, miễn là các thao tác trên hệ thống tệp là nguyên tử.

Thực hiện

import os, sys 

lock_file_path = ".lock_script" 

def lock_mutex(): 
    if os.path.exists(lock_mutex_path): 
     print "Error: script was already activated." 
     sys.exit(-1) 

    else: 
     file = open(lock_mutex_path, 'w') 

def unlock_mutex(): 
    assert(os.path.exists(lock_mutex_path)) 
    os.remove(lock_mutex_path) 

def main(): 

    try: 
     lock_mutex() 

     # do something 

     unlock_mutex() 

    except: 
     unlock_mutex() 

if __name__ == "__main__": 
    main() 

Vấn đề

Làm thế nào để đảm bảo lock_mutex()unlock_mutex() là nguyên tử?

+0

Bạn không muốn gọi tập lệnh nếu nó hoạt động đúng không? – Artur

+0

Trong sự tò mò, kịch bản bắt đầu như thế nào mà đây là một mối quan tâm? – ratatoskr

+2

Tôi không nghĩ giải pháp của bạn là giải pháp * ngây thơ *. Trong thực tế, nó là khá phổ biến cho một để tạo ra một tập tin khóa để kiểm tra xem kịch bản đang chạy. – aIKid

Trả lời

1

Tôi sử dụng người giám sát (http://supervisord.org/) để chạy nội dung trong Linux. Nó chạy Django, Celeryd và như vậy và đảm bảo rằng họ được khởi động lại trong trường hợp họ kết thúc bất ngờ.

Nhưng cũng có thể đặt các tùy chọn để các lệnh không được khởi động hoặc khởi động lại tự động khi nó kết thúc: autostart = false, autorestart = false, starseconds = 0. Tôi sử dụng nó cho những công việc cron này.

Trong cron tôi đặt lệnh "supervisorctl start myscript", không có gì nếu myscript đã chạy dưới sự giám sát, và nếu không thì bắt đầu nó.

Hoạt động hoàn hảo, bất kể ngôn ngữ mà tập lệnh được viết.

3

Vì bạn đang sử dụng Linux, bạn có thể tận dụng flock:

import os 
import fcntl 
import time 

def main(): 
    # acquire the prog lock 
    if not prog_lock_acq('singleton.lock'): 
    print("another instance is running") 
    exit(1) 

    print("program is running-press Ctrl+C to stop") 
    while True: 
    time.sleep(10) 

def prog_lock_acq(lpath): 
    fd = None 
    try: 
    fd = os.open(lpath, os.O_CREAT) 
    fcntl.flock(fd, fcntl.LOCK_NB | fcntl.LOCK_EX) 
    return True 
    except (OSError, IOError): 
    if fd: os.close(fd) 
    return False 

if __name__ == '__main__': 
    main() 

Nó không quan trọng mà chúng tôi rời khỏi tập tin mở sau khi thoát khỏi các prog_lock_acq bởi vì khi các lối ra quá trình, nó sẽ được tự động đóng bởi hệ điều hành. Ngoài ra, nếu bạn thoát khỏi tùy chọn LOCK_NB, cuộc gọi flock sẽ chặn cho đến khi quá trình chạy hiện tại thoát. Tùy thuộc vào trường hợp sử dụng của bạn, điều đó có thể hữu ích.

Lưu ý rằng chúng tôi sẽ không xóa tệp khi thoát. Nó không quan trọng. Sự tồn tại của tập tin không chỉ ra một quá trình trực tiếp - khóa đó thực hiện. Vì vậy, ngay cả khi bạn giết quá trình của bạn với kill -9, khóa vẫn được phát hành. Tuy nhiên, có một báo trước: nếu bạn hủy liên kết tệp khóa trong khi quá trình đang chạy, khi phiên bản tiếp theo của quy trình được chạy, nó sẽ tạo một tệp mới sẽ không có khóa và sẽ chạy tốt sẽ vi phạm thiết kế singleton của chúng tôi. Bạn có thể làm điều gì đó thông minh với một thư mục để ngăn chặn việc hủy liên kết nhưng tôi không chắc chắn mức độ mạnh mẽ của nó.

Các vấn đề liên quan