gpt4 book ai didi

ruby - 将成功和失败处理程序传递给 ActiveJob

转载 作者:数据小太阳 更新时间:2023-10-29 09:03:43 26 4
gpt4 key购买 nike

我有一个 ActiveJob,它应该通过 HTTP 从外部系统加载一段数据。该作业完成后,我想排队执行一些后处理的第二个作业,然后将数据提交到不同的外部系统。

我不想让第一份工作知道第二份工作,因为

  1. 封装
  2. 可重用性
  3. 基本上这与第一份工作无关

同样,我不希望第一份工作关心如果数据加载失败接下来会发生什么——也许用户会收到通知,也许我们在超时后重试,也许我们只是记录它并放弃我们的手—— - 同样,它可能会根据异常的详细信息而有所不同,并且作业不需要包含该逻辑或与其他系统的连接来处理它。

在 Java 中(这是我最有经验的地方),我可以使用像 Guava 的 ListenableFuture 这样的东西。在事后添加成功和失败回调:

MyDataLoader loader = new MyDataLoader(someDataSource)
ListenableFuture<Data> future = executor.submit(loader);
Futures.addCallback(future, new FutureCallback<Data>() {
public void onSuccess(Data result) {
processData(result);
}
public void onFailure(Throwable t) {
handleFailure(t);
}
});

不过,ActiveJob 似乎没有提供这种外部回调机制——我可以从 relevant 中得到最好的解释。 sections在“Active Job Basics”中,after_performrescue_from 只能从作业类中调用。并且 after_peform 并不是为了区分成功和失败。

所以我能想出的最好办法(我并不是说它很好)是将几个 lambda 传递给作业的 perform 方法,因此:

class MyRecordLoader < ActiveJob::Base

# Loads data expensively (hopefully on a background queue) and passes
# the result, or any exception, to the appropriate specified lambda.
#
# @param data_source [String] the URL to load data from
# @param on_success [-> (String)] A lambda that will be passed the record
# data, if it's loaded successfully
# @param on_failure [-> (Exception)] A lambda that will be passed any
# exception, if there is one
def perform(data_source, on_success, on_failure)
begin
result = load_data_expensively_from data_source
on_success.call(result)
rescue => exception
on_failure.call(exception)
end
end

end

(旁注:我不知道用于将 lambda 声明为参数的 yardoc 语法是什么。这看起来是否正确,或者,如果不正确,是否合理?)

然后调用者必须传递这些:

MyRecordLoader.perform_later(
some_data_source,
method(:process_data),
method(:handle_failure)
)

这并不糟糕,至少在调用端是这样,但它看起来很笨拙,我忍不住怀疑这有一个我只是没有找到的通用模式。而且我有点担心,作为一个 Ruby/Rails 新手,我只是让 ActiveJob 去做一些它一开始就不想做的事情。我发现的所有 ActiveJob 示例都是“即发即忘”——异步“返回”结果似乎不是 ActiveJob 用例。

此外,我不清楚这是否适用于像 Resque 这样在单独进程中运行作业的后端。

执行此操作的“Ruby 方式”是什么?


更新:作为hinted at通过 dre-hh,ActiveJob 证明不是这里的正确工具。它也不可靠,而且对于这种情况来说过于复杂。我切换到Concurrent Ruby相反,它更适合用例,而且由于任务主要受 IO 限制,即使在 MRI 上也足够快,despite the GIL .

最佳答案

ActiveJob 不是像 future 或 promise 那样的异步库。

它只是一个在后台执行任务的界面。当前线程/进程没有收到此操作的结果。

比如使用Sidekiq作为ActiveJob队列时,会将perform方法的参数序列化到redis store中。在您的 Rails 应用程序上下文中运行的另一个守护进程将监视 Redis 队列并使用序列化数据实例化您的工作人员。

所以传递回调可能没问题,但是为什么要将它们作为另一个类的方法。如果回调是动态的(在不同的调用中发生变化),则传递回调是有意义的。但是,当您在调用类上实现它们时,请考虑将这些方法移动到您的工作人员类中。

关于ruby - 将成功和失败处理程序传递给 ActiveJob,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29085054/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com