Apscheduler Python не останавливает выполнение функции

#python #flask #scheduled-tasks #apscheduler

#python #flask #запланированные задачи #apscheduler

Вопрос:

Я пытаюсь выполнить свою функцию распознавания лиц и использовать Apscheduler для запуска функции только между определенным временем. Я могу запустить функцию правильно, но end_time параметр, похоже, вообще не работает, функция просто продолжает работать, пока не будет отключена вручную.

Вот маршрут, который запускает расписание:

 @app.route("/schedule/start", methods = ['POST'])
    def create():
        sched = BlockingScheduler()
        sched.add_job(detection, 'cron', start_date='2020-10-01 15:33:00', end_date='2020-10-01 15:33:05')

    sched.start()


    return 'Schedule created.'
  

У меня есть While True условие в моей detection функции, вся логика определения выполняется внутри нее. Может ли это быть причиной, по которой он никогда не останавливается, даже если я определил время остановки? Как я могу исправить эту проблему?

Редактировать. Цикл While из моей detection функции (удалены ненужные части):

 while True:
        
    frame = stream.read()

    frame = imutils.resize(frame, width=900)
    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    frame = np.dstack([frame, frame, frame])
    # frame = cv2.flip(frame, 0)
    faces = faceCascade.detectMultiScale(
                        frame,
                        scaleFactor=1.1,
                        minNeighbors=3,
                        # minSize=(10, 10),
                        # maxSize=(50, 50),
                        # flags=cv2.CASCADE_SCALE_IMAGE
                )

    for (x, y, w, h) in faces:
        name = str(currentframe)   '.jpg'
        print('Creating...'   name)
        cv2.imwrite(os.path.join(parent_dir, name), frame)

        currentframe  = 1

        if cv2.waitKey(1) amp; 0xFF == ord('q'):
            break
  

Редактировать2. Я попробовал, как предложено ниже, и получил эту ошибку: TypeError: func must be a callable or a textual reference to one .

Я также хотел бы интегрировать возможность ручного запуска и остановки моей функции распознавания лиц. Я могу сделать это так:

 @app.route("/start", methods = ['POST'])
def start():
    os.environ['run'] = 'running'
    detection()

    return 'Detection started'


@app.route("/stop", methods = ['POST'])
def stop():
    os.environ['run'] = 'stop'    

    return 'Detection stopped.'
  

А затем в моем detection.py я просто проверяю переменную среды в начале моего цикла while:

 while True:
        if os.environ.get('run') == 'stop':
            stream.stream.release()
            exit()
  

Я бы хотел интегрировать в это функцию планирования. Я бы не хотел создавать отдельные функции, потому что я хочу иметь возможность вручную останавливать обнаружение, начатое с schedule . Любые советы, как я мог бы этого добиться?

Редактировать3. Теперь расписание работает. Ручной запуск также работает, и остановка работает в том смысле, что она перестает обнаруживать лица. Функция, запущенная с schedule, все еще продолжает работать, хотя она просто вообще не переходит к части обнаружения, потому что есть os.environ['run'] = 'stop' -flag . Есть идеи, как я мог бы остановить выполнение функции? Это проверка цикла, которую я имею:

 while True:
    if self.end_date <= datetime.now() or os.environ.get('run') == 'stop':
        stream.stream.release()
        exit()
  

При запуске вручную функция остановки работает, как и предполагалось, но при остановке запланированного задания она продолжает цикл до тех пор, пока не будет выполнено время end_date.

Комментарии:

1. Не могли бы вы поделиться фрагментом кода while True , который у вас есть в detection методе?

2. Конечно, отредактировал его в мой вопрос.

3. Время окончания — это только последнее время, когда (повторно) запускается полезная нагрузка. Это не время, когда функция останавливается — в generic в Python такого нет.

4. Что я понял об Apscheduler, он должен останавливать выполнение при выполнении end_date параметра. Не могли бы вы, пожалуйста, проверить мое второе редактирование из моего исходного сообщения? Хотелось бы услышать, есть ли у вас какие-либо мысли по этому поводу.

Ответ №1:

У вас должно быть какое-то условие, которое завершит ваш цикл while, поскольку теперь он бесконечен, передайте время начала / окончания и преобразуйте в дату-время и попытайтесь соответствовать while end_date_time =< now: , а затем завершите задачу. Если вам нужно передать даты начала / окончания, возможно, преобразуйте вашу detection функцию в класс и при инициализации передайте end_date , когда вы хотите, чтобы ваше задание cron остановилось.

 # detection.py
from datetime import datetime

class Detection:
    def __init__(self, end_date):
        self.end_date = datetime.strptime(end_date, '%Y-%m-%d %H:%M:%S.%f')

    def detection(self):
        print(self.end_date)
        while self.end_date <= datetime.utcnow():
            print('works')



# routes.py
# And then do it like this when starting cron
import Detection

def create():
    start_date = '2020-10-02 01:48:00.192386'
    end_date = '2020-10-02 05:50:00.192386'
    dt = Detection(end_date)
    sched = BlockingScheduler()
    sched.add_job(dt.detection, 'cron', start_date=start_date, end_date=end_date)

    sched.start()


    return 'Schedule created.'



  

Это должно решить проблему

Комментарии:

1. Я получаю эту ошибку: TypeError: func must be a callable or a textual reference to one

2. @ir_optim, я обновил пример кода, проверьте его сейчас

3. Спасибо. Заставил его работать с небольшими изменениями. Не могли бы вы проверить мой edit3 из исходного сообщения, если у вас есть несколько советов по остановке вручную, я хотел бы их услышать!

4. @lr_optim в вашем цикле while у вас есть os.environ.get('running_flag') == 'stop' while в заданном вами маршруте stop os.environ['run'] = 'stop' , так running_flag != run что, возможно, это проблема, поскольку цикл detection while пытается получить os.environ.get('running_flag') , и если он не установлен None , вы пытаетесь сравнить None == 'stop' , что всегда False .

5. Похоже, что route end() и the cron-job не используют одни и те же переменные среды. Вам нужно найти способ передать это run='stop' detection без использования os.environ