我有一个共享资源,一次只能由一个会话使用,如何向其他会话发信号通知当前正在使用该资源?
在Java或C中,我会使用互斥信号量来协调线程,如何在Rails中实现?我是否定义了一个新的环境变量并使用它来协调会话?
一小段代码片段和答案将非常有用。
答案 0 :(得分:2)
由于你的Rails实例在使用Nginx或Apache时可以在不同的进程中运行(没有像线程一样的共享内存),我想唯一的解决方案是使用文件锁:
lock = File.new("/lock/file")
begin
lock.flock(File::LOCK_EX)
# do your logic here, or share information in your lock file
ensure
lock.flock(File::LOCK_UN)
end
答案 1 :(得分:1)
我会考虑使用Redis锁定资源。
这具有跨多个服务器工作且不将锁定时间限制为当前HTTP请求的生存期的优点。
答案 2 :(得分:0)
Ruby有Mutex class可能会做你想要的,虽然它不能跨进程工作。我很抱歉,我不知道给你一个示例代码片段。以下是文档所说的内容:“Mutex实现了一个简单的信号量,可用于协调对来自多个并发线程的共享数据的访问。”
答案 3 :(得分:0)
您可以使用acts_as_lockable_by宝石来做到这一点。
想象一下,共享资源是一个Patient
ActiveRecord类,该类只能由单个用户访问(您可以将其替换为session_id),如下所示:
class Patient < ApplicationRecord
acts_as_lockable_by :id, ttl: 30.seconds
end
然后您可以在控制器中执行此操作:
class PatientsController < ApplicationController
def edit
if patient.lock(current_user.id)
# It will be locked for 30 seconds for the current user
# You will need to renew the lock by calling /patients/:id/renew_lock
else
# Could not lock the patient record which means it is already locked by another user
end
end
def renew_lock
if patient.renew_lock(current_user.id)
# lock renewed return 200
else
# could not renew the lock, it might be already released
end
end
private
def patient
@patient ||= Patient.find(params[:id])
end
end
这是一个解决方案,它使用最少的代码并跨RoR机器/服务器集群工作,而不仅仅是在一个服务器上本地(例如使用文件锁定),因为gem使用redis
作为锁定/信号代理。 lock
,unlock
和renew_lock
方法都是原子和线程安全的;)