0

我有一个一次只能由一个会话使用的共享资源,我如何向其他会话发出该资源当前正在使用的信号?

在 Java 或 CI 中会使用互斥信号量在线程之间进行协调,我如何在 Rails 中实现这一点?我是否定义了一个新的环境变量并使用它在会话之间进行协调?

一个小代码片段以及答案将非常有帮助。

4

4 回答 4

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
于 2012-05-14T16:54:50.183 回答
1

我会考虑使用 Redis 来锁定资源。

这具有跨多个服务器工作的优点,并且不会将锁定时间限制为当前 HTTP 请求的生命周期。

于 2018-11-06T15:14:18.450 回答
0

Ruby 有一个Mutex 类,它可以做你想做的事,尽管它不能跨进程工作。我很抱歉,虽然我知道的不够多,无法给你一个示例代码片段。文档是这样说的:“Mutex 实现了一个简单的信号量,可用于协调对来自多个并发线程的共享数据的访问。”

于 2012-05-14T17:34:15.883 回答
0

您可以使用acts_as_lockable_by gem 来做到这一点。

假设共享资源是一个PatientActiveRecord 类,只能由单个用户访问(您可以将其替换为 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 机器/服务器集群工作,而不仅仅是在一个服务器上本地(如使用文件锁),因为 gemredis用作锁/信号量代理。,lock和方法都是原子的和线程安全的; unlock)renew_lock

于 2018-11-06T14:54:53.717 回答