我有一个工作流程,需要每隔30秒钟唤醒一次并轮询数据库获取更新,然后执行相应的操作,再回到睡眠状态。暂且不考虑数据库轮询不可扩展等类似问题,使用监管器、工作者、任务等方法,最佳的工作流程结构是什么?
我列出了几个想法以及我的优缺点分析,请帮助我找出最符合Elixir理念的方法。(顺便说一下,我还很新于Elixir。)
1. 通过函数调用进行无限循环
只需在其中放置一个简单的递归循环,例如:
这样做的好处是它位于监管器内部,但似乎滥用了监管器。它不仅用于错误捕获和重启,还用于循环。
(注意:可能可以使用Task.Supervisor代替常规监管器,但我只是没有理解。)
基本上,将1和2结合起来,使其成为使用无限递归循环的任务(Task)。现在它由监管器管理,如果崩溃则会重新启动,但不会像正常工作流程的一部分那样反复重启。这是目前我最喜欢的方法。
我的担忧是我可能错过了一些基本的OTP结构。例如,我熟悉Agent和GenServer,但最近才发现Task。也许有一种专门针对这种情况的Looper,或者Task.Supervisor的某种用例涵盖了它。
我列出了几个想法以及我的优缺点分析,请帮助我找出最符合Elixir理念的方法。(顺便说一下,我还很新于Elixir。)
1. 通过函数调用进行无限循环
只需在其中放置一个简单的递归循环,例如:
def do_work() do
# Check database
# Do something with result
# Sleep for a while
do_work()
end
我在跟随构建网络爬虫的教程时看到了类似的内容。
我在这里有一个担忧,由于递归导致无限堆栈深度,这最终会导致堆栈溢出,因为我们在每个循环结束时都进行递归。这种结构在Elixir标准任务指南中使用,所以我可能对堆栈溢出问题是错误的。
更新 - 如答案中所述,Elixir中的尾调用递归意味着堆栈溢出在这里不是问题。在末尾调用自身的循环是一种接受的方式来进行无限循环。
2. 使用任务,每次重新启动
基本思想是使用一个运行一次然后退出的任务(Task),但将其与一个具有“一对一”重启策略的监管器(Supervisor)配对,因此每次完成后都会重新启动。任务检查数据库,睡眠,然后退出。监管器看到退出并启动一个新的任务。这样做的好处是它位于监管器内部,但似乎滥用了监管器。它不仅用于错误捕获和重启,还用于循环。
(注意:可能可以使用Task.Supervisor代替常规监管器,但我只是没有理解。)
基本上,将1和2结合起来,使其成为使用无限递归循环的任务(Task)。现在它由监管器管理,如果崩溃则会重新启动,但不会像正常工作流程的一部分那样反复重启。这是目前我最喜欢的方法。
我的担忧是我可能错过了一些基本的OTP结构。例如,我熟悉Agent和GenServer,但最近才发现Task。也许有一种专门针对这种情况的Looper,或者Task.Supervisor的某种用例涵盖了它。