【问题标题】:how to controller (start/kill) a background process (server app) in ruby如何在 ruby​​ 中控制(启动/终止)后台进程(服务器应用程序)
【发布时间】:2010-01-02 22:18:09
【问题描述】:

我正在尝试通过 ruby​​ 为集成测试(实际上是规范)设置服务器,但不知道如何控制该过程。

所以,我想做的是:

  1. 为我的 gem 运行一个执行集成规范的 rake 任务
  2. 任务需要先启动一个服务器(我用webrick),然后运行规范
  3. 执行规范后,它应该杀死 webrick,所以我不会留下一些未使用的后台进程

webrick 不是必需的,但它包含在 ruby​​ 标准库中,因此能够使用它会很棒。

希望有人能提供帮助!

ps。我在 linux 上运行,所以在 windows 上工作不是我的主要优先事项(现在)。

【问题讨论】:

    标签: ruby process webrick


    【解决方案1】:

    标准方法是使用系统函数 fork(复制当前进程)、exec(将当前进程替换为可执行文件)和 kill(向进程发送信号以终止它)。

    例如:

    pid = fork do
      # this code is run in the child process
      # you can do anything here, like changing current directory or reopening STDOUT
      exec "/path/to/executable"
    end
    
    # this code is run in the parent process
    # do your stuffs
    
    # kill it (other signals than TERM may be used, depending on the program you want
    # to kill. The signal KILL will always work but the process won't be allowed
    # to cleanup anything)
    Process.kill "TERM", pid
    
    # you have to wait for its termination, otherwise it will become a zombie process
    # (or you can use Process.detach)
    Process.wait pid
    

    这应该适用于任何类 Unix 系统。 Windows 以不同的方式创建进程。

    【讨论】:

    • 太棒了。非常感谢你。在尝试时,我有一个几乎相同的“解决方案”,几乎可以工作,但不幸的是我不知道它在哪里不同。我还需要在分叉进程后添加一个睡眠,以等待服务器可用。谢谢!
    • 我能够重现差异。我运行 Kernel#system 而不是 Kernel#exec。 Kernel#exec “通过运行给定的外部命令替换当前进程”,其中 Kernel#system “在子 shell 中执行命令”。
    • 即使 ruby​​ 脚本退出,子进程还能保持存活吗?
    【解决方案2】:

    我只需要做类似的事情,这就是我想出的。 @Michael Witrant 的回答让我开始了,但我改变了一些东西,比如使用 Process.spawn 而不是 fork (newer and better)。

    # start spawns a process and returns the pid of the process
    def start(exe)
        puts "Starting #{exe}"
        pid = spawn(exe)
        # need to detach to avoid daemon processes: http://www.ruby-doc.org/core-2.1.3/Process.html#method-c-detach
        Process.detach(pid)
        return pid
    end
    
    # This will kill off all the programs we started
    def killall(pids)
      pids.each do |pid|
          puts "Killing #{pid}"
          # kill it (other signals than TERM may be used, depending on the program you want
          # to kill. The signal KILL will always work but the process won't be allowed
          # to cleanup anything)
          begin
            Process.kill "TERM", pid
    
            # you have to wait for its termination, otherwise it will become a zombie process
            # (or you can use Process.detach)
            Process.wait pid
          rescue => ex
            puts "ERROR: Couldn't kill #{pid}. #{ex.class}=#{ex.message}"
          end
      end
    end
    
    # Now we can start processes and keep the pids for killing them later
    pids = []
    pids << start('./someprogram')
    
    # Do whatever you want here, run your tests, etc. 
    
    # When you're done, be sure to kill of the processes you spawned
    killall(pids)
    

    这就是她写的所有内容,试一试,让我知道它是如何工作的。

    【讨论】:

      【解决方案3】:

      我尝试过 fork,但是当 ActiveRecord 参与这两个进程时,它会出现一些问题。我建议 Spawn 插件 (http://github.com/tra/spawn)。它只分叉,但会处理 ActiveRecord。

      【讨论】:

      • 如果您需要 ar,您的解决方案可能是可行的方法。所以谢谢。但我真的不需要使用 ar。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-04-03
      • 1970-01-01
      • 1970-01-01
      • 2011-08-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多