我必须在Erlang中实现文件监视器功能:应该有一个进程列出文件,如果是特定目录,并在文件出现时执行某些操作。
我看看OTP。所以目前我有以下想法: 1.创建将控制gen_servers的Supervisor(每个文件夹一个服务器) 2.为我要监视的每个文件夹创建WatchServer - gen_server。 3.创建ProcessFileServer - 应该对文件执行某些操作的gen服务器)假设复制到不同的文件夹=
所以第一个问题:WatchServer不应该等待请求,它应该以预定义的间隔生成一个。
目前我已在init / 1函数中创建了一个计时器,并在handle_info函数中处理on_timer事件。
现在问题: 1.有更好的想法吗? 2.如何通知ProcessFileServer找到的文件?它对我来说,独立创建WatchServers和ProcessServers会更方便,但在这种情况下我不知道向谁发送消息?
可能有一些类似的项目/库可用吗?
答案 0 :(得分:4)
如果您使用的是Linux,则可以使用inotify。它是一个内核服务,允许您订阅文件系统事件。不要轮询文件系统,让文件系统给你打电话。
您可以尝试https://github.com/massemanet/inotify来观察您的目录。
乌尔夫
答案 1 :(得分:2)
在Erlang中,创建流程(与其他系统相比的数量级)非常便宜。
因此,我建议每次出现要处理的新文件时都创建一个新的ProcessFileServer。完成后,只需使用退出原因normal
终止流程。
我建议采用以下结构:
top_supervisor
|
+-----------------------+-------------------------+
| |
directory_supervisor processing_supervisor
| simple_one_for_one
+----------+-----...-----+ |
| | | starts children transient
| | | |
dir_watcher_1 dir_watcher_2 dir_watcher_n +-------------+------+---...----+
| | |
proc_file_1 proc_file_2 proc_file_n
当dir_watcher
注意到新文件出现时。它使用文件的额外参数调用processing_supervisor
s supervisor:start_child\2
函数,例如。
processing_supervisor
应该使用transient
重新启动政策启动其子级。
因此,如果其中一个proc_file
服务器崩溃,它将重新启动,但当它们以退出原因normal
终止时,它们不会重新启动。所以你完成后就退出normal
,当发生其他事情时崩溃。
如果你没有过头,那么文件的循环轮询就可以了。如果由于此轮询而导致系统加载,您可以在内核通知系统(例如FreeBSD KQUEUE或MacOSX上构建的更高级别服务)上进行调查,以便在文件出现在目录中时向您发送消息。然而,这些服务具有复杂性,因为如果发生太多事件,他们必须举手(否则他们不会提高性能,反之亦然)。所以你必须有一个强大的轮询解决方案作为后备。
因此,不要进行过早优化并从轮询开始,在必要时添加改进(将在dir_watcher
服务器中隔离)。
关于评论用作dir_watcher
进程的行为,因为它没有使用gen_servers
个大部分功能:
仅使用部分gen_servers
可能性没有问题,事实上不使用全部内容是很常见的。在您的情况下,您只需在init
中设置一个计时器,然后使用handle_info
来完成您的工作。 gen_server
的其余部分只是未更改的模板。
如果您以后想要更改轮询频率等参数,则很容易添加到此。
gen_fsm
使用率较低,因为它只适用于非常有限的模型而且不够灵活。我只在它真正符合要求的情况下使用它(几乎从不这样做)。
如果您只想要一个简单的普通Erlang服务器,可以使用proc_lib
中的spawn函数来获得在主管下运行的最小功能。
编写更自然的Erlang代码并且仍具有OTP优势的一种有趣的方法是plain_fsm
,这里有选择性接收和灵活的消息处理所需的优势,尤其是在处理与良好功能配对的协议时OTP。
说完这一切:如果我写一个dir_watcher
,我只需要使用gen_server
并仅使用我需要的东西。未使用的功能并没有真正花费你任何东西,每个人都知道它的作用。
答案 2 :(得分:2)
我根据民意调查编写了这样一个图书馆。 (将它扩展为在支持它的平台上使用inotify会很好。)它原本打算用于EUnit,但我转而成为一个单独的项目。你可以在这里找到它: