链接在Ruby中运行线程的方法

时间:2015-12-08 07:47:17

标签: ruby-on-rails ruby multithreading

我有4个任务需要时间,每个任务都取决于之前的任务。

如,

  

任务1 - 克隆git repo

     

任务2 - 使用配置文件初始化仓库

     

任务3 - 处理仓库

     

任务4 - 处理后将结果存储在db中

现在,这些所有任务都将在线程上运行,我试图在单独的方法中分离所有这4个任务,这些方法运行一个线程并启动任务。

我无法弄清楚如何将这4种方法链接在一起,仍然可以从下一种方法中使用的最后一种方法得到结果。

在方法中分离这些步骤的主要原因是因为我可以直接从步骤3开始并在某些情况下完全跳过上一步。

def clone_repo(url)
  Thread.new do
    # clone the repo
    # change the status in db
  end
end

def init_repo(repo)
  Thread.new do
    # init config files
    # change the status in db
  end
end

def process_repo(repo)
  Thread.new do
    # process repo
    # change the status in db
    # return or do something with the results to use it in next method
  end
end

def store_results(results)
  Thread.new do
    # store in db
    # change the status in db
  end
end

我可以朝着解决问题的任何方向前进,只想要一种重构的方法来解决这个问题。

1 个答案:

答案 0 :(得分:1)

如果你绝对需要在方法内部启动一个线程(而不是在它们周围,这会使任务更容易),你可以为每个任务使用一个互斥锁,初始化为锁定并在相应的任务完成时释放,所以下一个依赖的线程在尝试时在开始时锁定它将等待。 如果不需要任务 - 只需在不运行的情况下解锁

编辑:添加了示例结构:

class SomeRepoJob

  def perform_in_thread
    Thread.new do
      perform
    end
  end

  def perform
    clone_repo
    init_config
    results = process_repo
    store_results results if results
  rescue => e
    #do some error reporting if needed
  end


  private

  def set_db_status status
    # here you can mark task as "#{status}_started"
    yield
    # change the status in db
  rescue
    # revert status on failure
    raise
  end

  def repo_is_cloned?
    File.exists?(...)
  end

  def clone_repo(url)
    set_db_status(:cloned){
      unless repo_is_cloned?
        # clone the repo
      end
    }
  end

  def config_exists_and_valid?
    File.exists? ...
    # some config check and validation
  end

  def init_config(repo)
    set_db_status(:inited_config){
      unless config_exists_and_valid?
        # init config files
      end
    }
  end

  def processed?
    # somehow check if processing is needed, or always return false
  end

  def process_repo(repo)
    set_db_status(:processed_not_stored){
      unless processed?
        # process repo
        results
      else
        results = read_results
      end
      return results
    }
  end

  def results_stored? results
    #...
  end

  def store_results(results)
    set_db_status(:stored_results){
      unless results_stored? results
        # store in db
      end
    }
  end
end