点击按钮重启Rails ActiveJob/Sidekiq的实现方案咨询
搞定Rails播放任务的重启功能
嘿,我明白你想要实现的是——让正在循环播放歌曲的PlaylistJob能被重启,对吧?毕竟直接重复调用play方法的话,很可能会同时跑多个无限循环的Job,那可就乱套了。下面给你一套实用的方案:
第一步:给Job加个“停止开关”
Rails的Active Job本身没有直接终止运行中Job的方法,所以我们用Redis做个简单的信号标识,让Job自己检测要不要停止循环。修改你的PlaylistJob:
class PlaylistJob < ApplicationJob queue_as :default def perform(playlist) loop do # 检查有没有停止信号,有的话立刻退出循环 break if Redis.current.get("playlist_stop:#{playlist.id}") # 这里放你原来的播放逻辑——比如从playlist里取歌播放的代码 play_next_track(playlist) # 假设每首歌播放间隔5秒,根据你的实际情况调整 sleep 5 end # 任务结束后记得把停止信号删掉,避免影响下次启动 Redis.current.del("playlist_stop:#{playlist.id}") end private def play_next_track(playlist) # 你的播放逻辑实现,比如从playlist.songs里取下一首播放 end end
第二步:在控制器加restart动作
接下来写一个restart方法,先给当前运行的Job发停止信号,等它退出后再启动新的播放任务:
class PlaylistsController < ApplicationController # 你现有的play方法... def play if @playlist # 注意:flushall会清空整个Redis!如果你的Redis还有其他用途,换成只删相关键 # 比如改成 Redis.current.del("playlist_stop:*") system "redis-cli flushall" @playlist.update(current: true) Playlist.where.not(id: @playlist.id).update_all(current: false) PlaylistJob.perform_later(@playlist) # 这里加你的响应逻辑,比如redirect或者render end end def restart @playlist = Playlist.find(params[:id]) # 给当前播放任务发停止信号 Redis.current.set("playlist_stop:#{@playlist.id}", "1") # 稍微等一下,让旧Job有时间退出(时间根据你的循环间隔调整) sleep 2 # 调用play方法启动新任务,或者直接把play里的逻辑复制过来也行 play redirect_to playlists_path, notice: "播放任务已经重启啦!" end end
第三步:配置路由
最后在config/routes.rb里加上restart的路由,这样前端就能调用了:
resources :playlists do member do post :play post :restart end end
几个小提醒
- 关于
redis-cli flushall:这个操作会清空整个Redis数据库,如果你的应用还用Redis存缓存、其他Job数据之类的,一定要改成精准删除相关键,比如Redis.current.del("playlist_stop:*"),别把其他数据搞丢了。 - 如果你的后台用的是Sidekiq,也可以用Sidekiq的API直接终止Job,但用Redis信号的方式更通用,不管你用什么Active Job适配器都能生效。
- 前端可以给重启按钮加个确认提示,比如
<%= button_to "重启播放", restart_playlist_path(@playlist), data: { confirm: "确定要重启吗?" } %>,避免误操作。
这样操作之后,点击重启按钮,就能先停掉当前的播放循环,再重新启动新的播放任务啦~
内容的提问来源于stack exchange,提问作者Welp
相关产品推荐
相关产品推荐

