假设我有一个包含帖子的博客应用程序。创建帖子后,将创建一个工作程序来处理某些后台操作。我的情况是,在提交帖子表单后,我想显示某种加载消息(gif加载器等),当工作人员完成时,我想隐藏加载消息并显示工作人员提供的一些数据。我的问题是,工人完成工作并将其显示在用户前端的最佳沟通方式是什么。工人回调看起来像这样
def worker_finish
#message the user
end
答案 0 :(得分:13)
我认为你可能忽略了背景工作者的观点,基本上,你试图做的就是自我挫败。 - 如果用户提交表单并在控制器中排队作业,只是让用户等待工作人员开始和结束,你不仅要完成控制器自己完成的工作,而且你已经完成了使得这个过程变得更加复杂(并且这种类型的功能不是内置于resque或sidekiq)。
在卸载要由队列处理的作业时,您希望立即向客户端返回响应,即
class PostsController < ApplicationController
def create
@post = Post.create(params[:post])
BackgroundBlogOperation.enque(@post.id)
respond_with(@post)
end
end
然后将BackgroundBlogOperation类放入队列中,供工作人员完成并处理。如果您需要BackgroundBlogOperation工作程序在完成之后执行其他操作,则可以执行此操作,但这应该在作业本身内进行,以便工作人员可以对此负责。
如果您只是在创建帖子后尝试显示和隐藏微调器,而不重新加载页面,只需在单击提交按钮之前显示javascript微调器,并确保请求类型为js(add:remote =&gt; ;真实的形式)。然后创建一个类似于:
的javascript视图响应class PostsController < ApplicationController
respond_to :js, :only => [:create]
def create
@post = Post.create(params[:post])
BackgroundBlogOperation.enque(@post.id)
respond_with(@post)
end
end
并且create.js.erb还可以附加一条消息,告诉他们你在后台做的任何事情都已排队,如果它比创建帖子或其他更复杂。
$("#spinner").hide();
现在 - 虽然你最初要求的事情是任何目的(因为在完成工作时显示和隐藏微调器需要等待控制器完成操作) - 有些情况下显示给客户端作业已完成处理是有用的。
首先,我们定义一个后台处理实际有用的场景。假设您有一个按钮,当单击时,将从某些外部API中提取数据,并在从外部站点获取数据后,您正在根据响应执行数据库操作。这将是何时使用后台进程的一个很好的例子。基本上在控制器中你会做类似的事情:
class ApiController < ApplicationController
respond_to :js, :only => [:create]
def sync_tweets
TwitterApiJob.enque(current_user.twitter_username)
respond_with(message: 'Syncing Tweets')
end
end
现在,告诉用户推文完成同步的时间有点复杂,你有3个基本选项:
1)通过电子邮件通知用户(通常最差的选项imo) 2)使用某种html5或支持websocket的rails服务器来运行rails,并通过websocket向客户端发送推送,虽然非常酷,但在大多数情况下都是过度杀伤,超出了此响应的范围。如果你想看到你的选择,谷歌会推动websocket推送。 3)IMO最适用于大多数情况的选项,创建一个通知模型来处理各种用户通知,并在工作中,在工作完成后,执行类似
的操作Notification.create(:user_id => user.id, :message => 'Sync has finished', type => 'sync_complete')
然后,用户请求的下一页,在标题工具栏或任何地方,我会注意到用户有未读通知,提醒用户点击它。
---我想在你的帖子中你提到你正在使用resque。我尝试了resque并且它很不错,但是我发现它在生产中调试过于复杂,并且它使用了疯狂的内存 - 我建议你查看sidekiq如果你还没有,它使用redis也可以更快,因为它使用线程:
https://github.com/mperham/sidekiq
它更快,更清洁,更容易安装,imho。