如何从rake任务中提前返回?

我有一个rake任务,在开始时我做了一些检查,如果其中一个检查失败,我想从rake任务中提前返回,我不想执行任何剩余的代码。

我认为解决方案是在我想从代码返回的地方放置一个返回,但我得到以下错误

unexpected return
64777 次浏览

Rake任务基本上是一个块。一个块,除了lambdas,不支持return,但是你可以使用next跳到下一个语句,它在rake任务中具有在方法中使用return的相同效果。

task :foo do
puts "printed"
next
puts "never printed"
end

或者您可以移动方法中的代码并在方法中使用return。

task :foo do
do_something
end


def do_something
puts "startd"
return
puts "end"
end

我更喜欢第二种选择。

你可以在任务内部使用abort(message)来终止该任务并发送消息。

如果您想要退出rake任务而不打印“rake abort !”消息,那么您可以使用“abort”或“exit”。但是"abort"在救援块中使用时,会终止任务并打印整个错误(即使不使用——trace)。我用的是exit。

如果你需要打破多个块级别,你可以使用失败

例如

task :something do
[1,2,3].each do |i|
...
fail "some error" if ...
end
end

(参见https://stackoverflow.com/a/3753955/11543)。

我倾向于使用abort,这是在这种情况下更好的选择,例如:

task :foo do
something = false
abort 'Failed to proceed' unless something
end

返回错误❌

如果你返回一个错误(即1的退出码),你会想要使用abort,它也接受一个可选的字符串参数,将在退出时输出:

task :check do
  

# If any of your checks fail, you can exit early like this.
abort( "One of the checks has failed!" ) if check_failed?


end

在命令行中:

$ rake check && echo "All good"
#=> One of the checks has failed!

返回成功✅

如果你返回没有一个错误(即0的退出码),你会想使用exit,其中接受一个字符串参数。

task :check do
  

# If any of your checks fail, you can exit early like this.
exit if check_failed?
  

end

在命令行中:

$ rake check && echo "All good"
#=> All good

如果您在cron作业中使用它,或者需要根据rake任务是否成功进行后续操作,那么这一点很重要。


额外奖励:从没有stacktrace的rescue块返回一个Error。

默认情况下,如果你在rescue块中使用abort,它将输出整个堆栈跟踪,即使你只是使用abort而没有重新引发错误。

为了解决这个问题,你可以为exit命令提供一个非零退出码,比如:


task :check do


begin
do_the_thing_that_raises_an_exception
rescue => error
puts error.message
 

exit( 1 )
end


end

我使用了Simone Carletti建议的next方法,因为在测试rake任务时,abort实际上只是exit的包装器,并不是理想的行为。

例子:

task auto_invoice: :environment do
if Application.feature_disabled?(:auto_invoice)
$stderr.puts 'Feature is disabled, aborting.'
next
end