PageRenderTime 74ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/rq/jobrunner.rb

https://github.com/pjotrp/rq
Ruby | 110 lines | 86 code | 10 blank | 14 comment | 7 complexity | 26d3ad271fe02afbd32a68be7d1c1f7a MD5 | raw file
  1. unless defined? $__rq_jobrunner__
  2. module RQ
  3. #--{{{
  4. LIBDIR = File::dirname(File::expand_path(__FILE__)) + File::SEPARATOR unless
  5. defined? LIBDIR
  6. require 'drb/drb'
  7. require 'yaml'
  8. require LIBDIR + 'util'
  9. #
  10. # the JobRunner class is responsible for pre-forking a process/shell in
  11. # which to run a job. this class is utilized by the JobRunnerDaemon so
  12. # processes can be forked via a drb proxy to avoid actual forking during an
  13. # sqlite transaction - which has undefined behaviour
  14. #
  15. class JobRunner
  16. #--{{{
  17. $VERBOSE = nil
  18. include DRbUndumped
  19. attr :q
  20. attr :job
  21. attr :jid
  22. attr :cid
  23. attr :shell
  24. attr :command
  25. attr :stdin
  26. attr :stdout
  27. attr :stderr
  28. attr :data
  29. alias pid cid
  30. def initialize q, job
  31. #--{{{
  32. @q = q
  33. @job = job
  34. @jid = job['jid']
  35. @command = job['command']
  36. @shell = job['shell'] || 'bash'
  37. @sh_like = File::basename(@shell) == 'bash' || File::basename(@shell) == 'sh'
  38. @r,@w = IO::pipe
  39. @env = {}
  40. @env["PATH"] = [@q.bin, ENV["PATH"]].join(":")
  41. @job.fields.each do |field|
  42. key = "RQ_#{ field }".upcase.gsub(%r/\s+/,'_')
  43. val = @job[field]
  44. val = File.expand_path(File.join(@q.path,val)) if %w( stdin stdout stderr data).include?(field.to_s)
  45. @env[key] = "#{ val }"
  46. end
  47. @env['RQ'] = File.expand_path @q.path
  48. @env['RQ_JOB'] = @job.to_hash.to_yaml
  49. @stdin = @job['stdin']
  50. @stdout = @job['stdout']
  51. @stderr = @job['stderr']
  52. @data = @job['data']
  53. @stdin &&= File::join @q.path, @stdin # assume path relative to queue
  54. @stdout &&= File::join @q.path, @stdout # assume path relative to queue
  55. @stderr &&= File::join @q.path, @stderr # assume path relative to queue
  56. @data &&= File::join @q.path, @data # assume path relative to queue
  57. @cid =
  58. Util::fork do
  59. @env.each{|k,v| ENV[k] = v}
  60. ENV['RQ_PID'] = "#{ $$ }"
  61. @w.close
  62. STDIN.reopen @r
  63. argv =
  64. if @sh_like
  65. [ [@shell, "__rq_job__#{ @jid }__#{ File::basename(@shell) }__"], '--login' ]
  66. else
  67. [ [@shell, "__rq_job__#{ @jid }__#{ File::basename(@shell) }__"], '-l' ]
  68. end
  69. exec *argv
  70. end
  71. @r.close
  72. #--}}}
  73. end
  74. def run
  75. #--{{{
  76. command = @command.gsub %r/#.*/o, '' # kill comments
  77. path = @q.bin
  78. command =
  79. if @sh_like
  80. sin = "0<#{ @stdin }" if @stdin and File.exist?(@stdin)
  81. sout = "1>#{ @stdout }" if @stdout
  82. serr = "2>#{ @stderr }" if @stderr
  83. "( PATH=#{ path }:$PATH #{ command } ;) #{ sin } #{ sout } #{ serr }"
  84. else
  85. sin = "<#{ @stdin }" if @stdin
  86. sout = ">#{ @stdout }" if @stdout
  87. serr = ">&#{ @stderr }" if @stderr
  88. "( ( #{ command } ;) #{ sin } #{ sout } ) #{ serr }"
  89. end
  90. FileUtils::touch(@stdin) unless File.exist?(@stdin)
  91. @w.puts command
  92. @w.close
  93. #--}}}
  94. end
  95. #--}}}
  96. end # class JobRunner
  97. #--}}}
  98. end # module RQ
  99. $__rq_jobrunner__ = __FILE__
  100. end