将后台进程状态更新存储在文件中是否明智?
Is it wise to store background process status updates in a file?
我正在开发一个 ruby gem 来解析大量记录。这个 gem 将被不同的前端使用,其中一个是控制台 ruby 脚本,另一个是 rails 应用程序,它将作为后台作业启动。
我正在寻找一种方法,让前端通过一条消息告知作业的完成百分比和操作名称来了解作业的状态。例如:
5% Initializing...
我知道 delayed_job 可以利用名为 progress_job 的 gem,它将进度存储在 activerecord 中,sidekiq 使用 redis 具有类似的功能,但这将迫使我rails 应用到特定的后台作业后端,也不适用于非 rails 应用。
我正在考虑使用一个文件(也许json)来存储进度更新,但是半小时内每秒写入数百次文件似乎不是一个好习惯。
是否有更好的方法通知前端进度更新?
更新:
看了评论觉得没必要那么频繁更新状态。每 5/6 秒一次看起来是个好主意。
你在问题中提到了redis。为什么不在那里存储进度,除非您不想添加任何更多的依赖项?它对您的情况有一些有用的功能,例如到期时间。如果您不想使用 redis,我同意 spikerman 的观点,即在数据库中存储进度是一个很好的解决方案。基本上,写在文件里和写在数据库里是一样的,只是更乱。也许我没有很好地理解你的问题,但是你将如何处理多个并行作业?每个人都会创建自己的文件?或者所有作业都只有一个文件?这甚至可能吗? websockets 对我来说太过分了。
不是每 20 行更新一次,而是每 N 秒更新一次。在每一行之后,检查自上次更新以来已经过去了多少时间;如果它大于N,写一个更新。如果您的作业运行 30 分钟,那么每增加 1% 平均需要 18 秒,因此可能不需要每秒更新用户多次。
由于您将有两个或更多输出通道(终端、网络),它们的行为非常不同,我建议编写一个每个都可以实现的通用接口。这样处理数据的代码就可以调用例如output_obj.write
不关心 output_obj
是什么。
对于您的终端程序,我建议查看其他 Unixy 命令行工具在输出方面的行为方式。在最基本的情况下,他们将输出写入 $stdout
。大多数还接受文件名参数。有些会在将数据写入 $stdout
的同时将状态或进度信息写入 $stderr
,允许用户执行类似 tool in.txt > out.txt
的操作,并且在将数据输出重定向到文件(或管道)时仍然可以看到进度信息它到另一个工具)。
如果您的数据具有任何结构,JSON 作为一种序列化格式是有意义的。如果您的输出非常简单,您可能会考虑以表格格式打印它,将 $,
设置为 ENV['OFS']
(输出字段分隔符),或者在没有它的情况下,设置一些合理的默认值:
#/usr/bin/env ruby
$, = ENV['OFS'] || "\t"
print 'foo', 'bar', 'baz'
然后:
$ ruby tool.rb
foo bar baz
$ export OFS=';'
$ ruby tool.rb
foo;bar;baz
如有疑问,请遵循既定惯例。对你的输出感到厌烦;从不聪明。
对于您的 Web 前端,将更新写入文件系统意义不大。使用 ActiveRecord 或 Redis 或您的应用程序已在使用的任何内容。然后让浏览器轮询更新或使用 websockets 或其他。做最简单的事; optimize/streamline 以后有需要时再说。
我正在开发一个 ruby gem 来解析大量记录。这个 gem 将被不同的前端使用,其中一个是控制台 ruby 脚本,另一个是 rails 应用程序,它将作为后台作业启动。
我正在寻找一种方法,让前端通过一条消息告知作业的完成百分比和操作名称来了解作业的状态。例如:
5% Initializing...
我知道 delayed_job 可以利用名为 progress_job 的 gem,它将进度存储在 activerecord 中,sidekiq 使用 redis 具有类似的功能,但这将迫使我rails 应用到特定的后台作业后端,也不适用于非 rails 应用。
我正在考虑使用一个文件(也许json)来存储进度更新,但是半小时内每秒写入数百次文件似乎不是一个好习惯。
是否有更好的方法通知前端进度更新?
更新:
看了评论觉得没必要那么频繁更新状态。每 5/6 秒一次看起来是个好主意。
你在问题中提到了redis。为什么不在那里存储进度,除非您不想添加任何更多的依赖项?它对您的情况有一些有用的功能,例如到期时间。如果您不想使用 redis,我同意 spikerman 的观点,即在数据库中存储进度是一个很好的解决方案。基本上,写在文件里和写在数据库里是一样的,只是更乱。也许我没有很好地理解你的问题,但是你将如何处理多个并行作业?每个人都会创建自己的文件?或者所有作业都只有一个文件?这甚至可能吗? websockets 对我来说太过分了。
不是每 20 行更新一次,而是每 N 秒更新一次。在每一行之后,检查自上次更新以来已经过去了多少时间;如果它大于N,写一个更新。如果您的作业运行 30 分钟,那么每增加 1% 平均需要 18 秒,因此可能不需要每秒更新用户多次。
由于您将有两个或更多输出通道(终端、网络),它们的行为非常不同,我建议编写一个每个都可以实现的通用接口。这样处理数据的代码就可以调用例如output_obj.write
不关心 output_obj
是什么。
对于您的终端程序,我建议查看其他 Unixy 命令行工具在输出方面的行为方式。在最基本的情况下,他们将输出写入 $stdout
。大多数还接受文件名参数。有些会在将数据写入 $stdout
的同时将状态或进度信息写入 $stderr
,允许用户执行类似 tool in.txt > out.txt
的操作,并且在将数据输出重定向到文件(或管道)时仍然可以看到进度信息它到另一个工具)。
JSON 作为一种序列化格式是有意义的。如果您的输出非常简单,您可能会考虑以表格格式打印它,将 $,
设置为 ENV['OFS']
(输出字段分隔符),或者在没有它的情况下,设置一些合理的默认值:
#/usr/bin/env ruby
$, = ENV['OFS'] || "\t"
print 'foo', 'bar', 'baz'
然后:
$ ruby tool.rb
foo bar baz
$ export OFS=';'
$ ruby tool.rb
foo;bar;baz
如有疑问,请遵循既定惯例。对你的输出感到厌烦;从不聪明。
对于您的 Web 前端,将更新写入文件系统意义不大。使用 ActiveRecord 或 Redis 或您的应用程序已在使用的任何内容。然后让浏览器轮询更新或使用 websockets 或其他。做最简单的事; optimize/streamline 以后有需要时再说。