使用看门狗正确处理错误

时间:2019-01-10 07:59:27

标签: python exception-handling watchdog

我试图了解如何在Python中正确使用错误处理。 我正在使用看门狗在网络连接的光盘中寻找我的朋友。光盘暂时断开连接,然后再次连接,然后弹出错误。 “线程Thread-2中的异常:”

我有一个错误处理程序,但是我不确定我做的是否正确。

我是否应该在Observer.schedule步骤再尝试一次?

Python 3.6,Windows 10

if __name__ == '__main__':
    path = "P:\\03_auto\\Indata"
    observer = Observer()
    observer.schedule(MyHandler(), path, recursive=True)
    observer.start()

    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        observer.stop()

    observer.join()

3 个答案:

答案 0 :(得分:0)

好吧,我在评论中提到的sys.excepthook方法目前尚不可行。 bug已有十多年的历史,它使从threading.Thread派生的线程忽略sys.excepthook。该错误的消息线程中概述了一些变通办法,但我急于发布采用变通办法的答案,尤其是因为此臭虫似乎终于可以解决python 3.8了。

另一个选择是从看门狗的观察者派生自定义观察者。 我能想到的最基本的方法是围绕父级run()方法的包装:

class CustomObserver(Observer):

    def run(self):
        while self.should_keep_running():
            try:
                # Tweak the super call if you require compatibility with Python 2
                super().run()
            except OSError: 
            # You did not mention the excpetion class in your post.
            # Be specific about what you want to handle here
                # give the file system some time to recover
                time.sleep(.5)

快速浏览一下源代码,所有观察者似乎都从EventDispatcher.run()继承了run,因此您甚至可以省略包装器并直接重新实现该方法

class CustomObserver(Observer):

    def run(self):
        while self.should_keep_running():
            try:
                self.dispatch_events(self.event_queue, self.timeout)
            except queue.Empty:
                continue
            except OSError:
                time.sleep(.5)

但是,我的包装盒中没有安装该软件包,因此这些东西未经测试;您可能需要四处弄弄才能继续进行。 哦,请确保将OSError *替换为您情况下实际引发的任何异常类:)

修改:
*根据下面的@HenryYik的评论,网络驱动器断开连接似乎在Windows系统上引发了OSError(WinError 64:ERROR_NETNAME_DELETED)。我发现在这种情况下UNIX风格的操作系统可能会引发相同类型的异常,因此我更新了代码片段,现在使用OSError代替了我最初使用的FileNotFoundError

答案 1 :(得分:0)

我认为super().run()不是一个好的答案。 我已经用shmee的答案尝试了很多事情,但这并不是具体而毫无意义的。

以下是我的答案。 我已经完成了测试。

from watchdog.observers import Observer
from watchdog.events import PatternMatchingEventHandler


class Watcher :
    def __init__(self):
        self.observer = Observer()
        print('observer init...')

    def run(self):
        global osv_status
        try :            
            event_handler = MyHandler(patterns=["*.txt"])
            self.observer.schedule(event_handler, Directory, recursive=True)
            self.observer.start()
            osv_status = 1            

        except OSError as ex:
            print("OSError")
            time.sleep(.5)

            if self.observer.is_alive() is True:
                self.observer.stop()
                self.observer.join()
                print("Observer is removed [ ",osv_status," ]")
                osv_status = 2

        except Exception as ex:
            self.logger.exception("Exception ex :{0} ".format(ex))


class MyHandler(PatternMatchingEventHandler):
    def __init__(self,*args, **kwargs):
        super(MyHandler, self).__init__(*args, **kwargs)
        print("MyHandler Init")

    def on_created(self, event): 
        print('New file is created ',event.src_path)

        except Exception as ex:            
            self.logger.exception("Exception ex :{0} ".format(ex))


    def on_modified(self,event):
        print('File is modified ',event.src_path)
        try :
            doing()
        except Exception as ex:            
            self.logger.exception("Exception ex :{0} ".format(ex))


if __name__ == "__main__":
    .....
    osv_status = 0 # 0: ready, 1:start  2: halt
    wch =Watcher()
    wch.run()

    try :
        while(1):
            if is_Connect == False:
                sock_connect()
                print('sock_connect')

            time.sleep(1)
            if os.path.exists(Directory) is False and osv_status == 1:
                wch.observer.stop()
                wch.observer.join()
                print("Observer is removed [ ",osv_status," ]")
                osv_status = 0
            elif os.path.exists(Directory) is True and (osv_status == 0 or osv_status == 2):
                if wch.observer.is_alive() is False:
                    wch =Watcher()
                    wch.run()

答案 2 :(得分:0)

我还将其发布在相关主题here

这是我解决此问题的方法:

    from watchdog import observers
    from watchdog.observers.api import DEFAULT_OBSERVER_TIMEOUT, BaseObserver


    class MyEmitter(observers.read_directory_changes.WindowsApiEmitter):
        def queue_events(self, timeout):
            try:
                super().queue_events(timeout)
            except OSError as e:
                print(e)
                connected = False
                while not connected:
                    try:
                        self.on_thread_start()  # need to re-set the directory handle.
                        connected = True
                        print('reconnected')
                    except OSError:
                        print('attempting to reconnect...')
                        time.sleep(10)


    observer = BaseObserver(emitter_class=MyEmitter, timeout=DEFAULT_OBSERVER_TIMEOUT)
    ...

WindowsApiEmitter进行子类化以捕获queue_events中的异常。为了在重新连接后继续运行,看门狗需要重新设置目录句柄,我们可以使用self.on_thread_start()进行设置。

然后将MyEmitterBaseObserver一起使用,我们现在可以处理丢失和恢复与共享驱动器的连接。