queue_classic 2.0.0rc9 → 2.0.0rc10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/queue_classic/conn.rb +10 -12
- data/lib/queue_classic/queries.rb +5 -3
- data/lib/queue_classic/scrolls.rb +127 -0
- data/lib/queue_classic/worker.rb +43 -39
- data/lib/queue_classic.rb +20 -11
- data/readme.md +13 -1
- data/test/helper.rb +0 -2
- metadata +4 -3
    
        data/lib/queue_classic/conn.rb
    CHANGED
    
    | @@ -3,7 +3,7 @@ module QC | |
| 3 3 | 
             
                extend self
         | 
| 4 4 |  | 
| 5 5 | 
             
                def execute(stmt, *params)
         | 
| 6 | 
            -
                  log(" | 
| 6 | 
            +
                  log(:level => :debug, :action => "exec_sql", :sql => stmt.inspect)
         | 
| 7 7 | 
             
                  begin
         | 
| 8 8 | 
             
                    params = nil if params.empty?
         | 
| 9 9 | 
             
                    r = connection.exec(stmt, params)
         | 
| @@ -11,38 +11,36 @@ module QC | |
| 11 11 | 
             
                    r.each {|t| result << t}
         | 
| 12 12 | 
             
                    result.length > 1 ? result : result.pop
         | 
| 13 13 | 
             
                  rescue PGError => e
         | 
| 14 | 
            -
                    log( | 
| 14 | 
            +
                    log(:error => e.inspect)
         | 
| 15 15 | 
             
                    raise
         | 
| 16 16 | 
             
                  end
         | 
| 17 17 | 
             
                end
         | 
| 18 18 |  | 
| 19 19 | 
             
                def notify(chan)
         | 
| 20 | 
            -
                  log("NOTIFY")
         | 
| 20 | 
            +
                  log(:level => :debug, :action => "NOTIFY")
         | 
| 21 21 | 
             
                  execute('NOTIFY "' + chan + '"') #quotes matter
         | 
| 22 22 | 
             
                end
         | 
| 23 23 |  | 
| 24 24 | 
             
                def listen(chan)
         | 
| 25 | 
            -
                  log("LISTEN")
         | 
| 25 | 
            +
                  log(:level => :debug, :action => "LISTEN")
         | 
| 26 26 | 
             
                  execute('LISTEN "' + chan + '"') #quotes matter
         | 
| 27 27 | 
             
                end
         | 
| 28 28 |  | 
| 29 29 | 
             
                def unlisten(chan)
         | 
| 30 | 
            -
                  log("UNLISTEN")
         | 
| 30 | 
            +
                  log(:level => :debug, :action => "UNLISTEN")
         | 
| 31 31 | 
             
                  execute('UNLISTEN "' + chan + '"') #quotes matter
         | 
| 32 32 | 
             
                end
         | 
| 33 33 |  | 
| 34 34 | 
             
                def drain_notify
         | 
| 35 35 | 
             
                  until connection.notifies.nil?
         | 
| 36 | 
            -
                    log( | 
| 36 | 
            +
                    log(:level => :debug, :action => "drain_notifications")
         | 
| 37 37 | 
             
                  end
         | 
| 38 38 | 
             
                end
         | 
| 39 39 |  | 
| 40 40 | 
             
                def wait_for_notify(t)
         | 
| 41 | 
            -
                  log("waiting for notify timeout=#{t}")
         | 
| 42 41 | 
             
                  connection.wait_for_notify(t) do |event, pid, msg|
         | 
| 43 | 
            -
                    log( | 
| 42 | 
            +
                    log(:level => :debug, :action => "received_notification")
         | 
| 44 43 | 
             
                  end
         | 
| 45 | 
            -
                  log("done waiting for notify")
         | 
| 46 44 | 
             
                end
         | 
| 47 45 |  | 
| 48 46 | 
             
                def transaction
         | 
| @@ -70,7 +68,7 @@ module QC | |
| 70 68 | 
             
                end
         | 
| 71 69 |  | 
| 72 70 | 
             
                def connect
         | 
| 73 | 
            -
                  log( | 
| 71 | 
            +
                  log(:level => :debug, :action => "establish_conn")
         | 
| 74 72 | 
             
                  conn = PGconn.connect(
         | 
| 75 73 | 
             
                    db_url.host,
         | 
| 76 74 | 
             
                    db_url.port || 5432,
         | 
| @@ -80,7 +78,7 @@ module QC | |
| 80 78 | 
             
                    db_url.password
         | 
| 81 79 | 
             
                  )
         | 
| 82 80 | 
             
                  if conn.status != PGconn::CONNECTION_OK
         | 
| 83 | 
            -
                    log( | 
| 81 | 
            +
                    log(:level => :error, :message => conn.error)
         | 
| 84 82 | 
             
                  end
         | 
| 85 83 | 
             
                  conn
         | 
| 86 84 | 
             
                end
         | 
| @@ -90,7 +88,7 @@ module QC | |
| 90 88 | 
             
                end
         | 
| 91 89 |  | 
| 92 90 | 
             
                def log(msg)
         | 
| 93 | 
            -
                   | 
| 91 | 
            +
                  QC.log(msg)
         | 
| 94 92 | 
             
                end
         | 
| 95 93 |  | 
| 96 94 | 
             
              end
         | 
| @@ -3,9 +3,11 @@ module QC | |
| 3 3 | 
             
                extend self
         | 
| 4 4 |  | 
| 5 5 | 
             
                def insert(q_name, method, args, chan=nil)
         | 
| 6 | 
            -
                   | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 6 | 
            +
                  QC.log_yield(:action => "insert_job") do
         | 
| 7 | 
            +
                    s = "INSERT INTO #{TABLE_NAME} (q_name, method, args) VALUES ($1, $2, $3)"
         | 
| 8 | 
            +
                    res = Conn.execute(s, q_name, method, OkJson.encode(args))
         | 
| 9 | 
            +
                    Conn.notify(chan) if chan
         | 
| 10 | 
            +
                  end
         | 
| 9 11 | 
             
                end
         | 
| 10 12 |  | 
| 11 13 | 
             
                def lock_head(q_name, top_bound)
         | 
| @@ -0,0 +1,127 @@ | |
| 1 | 
            +
            require "thread"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Scrolls
         | 
| 4 | 
            +
              extend self
         | 
| 5 | 
            +
             | 
| 6 | 
            +
              def log(data, &blk)
         | 
| 7 | 
            +
                Log.log(data, &blk)
         | 
| 8 | 
            +
              end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              def log_exception(data, e)
         | 
| 11 | 
            +
                Log.log_exception(data, e)
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              module Log
         | 
| 15 | 
            +
                extend self
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                LOG_LEVEL = (ENV["QC_LOG_LEVEL"] || 3).to_i
         | 
| 18 | 
            +
                LOG_LEVEL_MAP = {
         | 
| 19 | 
            +
                  "fatal" => 0,
         | 
| 20 | 
            +
                  "error" => 1,
         | 
| 21 | 
            +
                  "warn"  => 2,
         | 
| 22 | 
            +
                  "info"  => 3,
         | 
| 23 | 
            +
                  "debug" => 4
         | 
| 24 | 
            +
                }
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                attr_accessor :stream
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                def start(out = nil)
         | 
| 29 | 
            +
                  # This allows log_exceptions below to pick up the defined output,
         | 
| 30 | 
            +
                  # otherwise stream out to STDERR
         | 
| 31 | 
            +
                  @defined = out.nil? ? false : true
         | 
| 32 | 
            +
                  sync_stream(out)
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                def sync_stream(out = nil)
         | 
| 36 | 
            +
                  out = STDOUT if out.nil?
         | 
| 37 | 
            +
                  @stream = out
         | 
| 38 | 
            +
                  @stream.sync = true
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                def mtx
         | 
| 42 | 
            +
                  @mtx ||= Mutex.new
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                def write(data)
         | 
| 46 | 
            +
                  if log_level_ok?(data[:level])
         | 
| 47 | 
            +
                    msg = unparse(data)
         | 
| 48 | 
            +
                    mtx.synchronize do
         | 
| 49 | 
            +
                      @stream.puts(msg)
         | 
| 50 | 
            +
                    end
         | 
| 51 | 
            +
                  end
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                def unparse(data)
         | 
| 55 | 
            +
                  data.map do |(k, v)|
         | 
| 56 | 
            +
                    if (v == true)
         | 
| 57 | 
            +
                      k.to_s
         | 
| 58 | 
            +
                    elsif v.is_a?(Float)
         | 
| 59 | 
            +
                      "#{k}=#{format("%.3f", v)}"
         | 
| 60 | 
            +
                    elsif v.nil?
         | 
| 61 | 
            +
                      nil
         | 
| 62 | 
            +
                    else
         | 
| 63 | 
            +
                      v_str = v.to_s
         | 
| 64 | 
            +
                      if (v_str =~ /^[a-zA-z0-9\-\_\.]+$/)
         | 
| 65 | 
            +
                        "#{k}=#{v_str}"
         | 
| 66 | 
            +
                      else
         | 
| 67 | 
            +
                        "#{k}=\"#{v_str.sub(/".*/, "...")}\""
         | 
| 68 | 
            +
                      end
         | 
| 69 | 
            +
                    end
         | 
| 70 | 
            +
                  end.compact.join(" ")
         | 
| 71 | 
            +
                end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                def log(data, &blk)
         | 
| 74 | 
            +
                  unless blk
         | 
| 75 | 
            +
                    write(data)
         | 
| 76 | 
            +
                  else
         | 
| 77 | 
            +
                    start = Time.now
         | 
| 78 | 
            +
                    res = nil
         | 
| 79 | 
            +
                    log(data.merge(:at => :start))
         | 
| 80 | 
            +
                    begin
         | 
| 81 | 
            +
                      res = yield
         | 
| 82 | 
            +
                    rescue StandardError, Timeout::Error => e
         | 
| 83 | 
            +
                      log(data.merge(
         | 
| 84 | 
            +
                        :at           => :exception,
         | 
| 85 | 
            +
                        :reraise      => true,
         | 
| 86 | 
            +
                        :class        => e.class,
         | 
| 87 | 
            +
                        :message      => e.message,
         | 
| 88 | 
            +
                        :exception_id => e.object_id.abs,
         | 
| 89 | 
            +
                        :elapsed      => Time.now - start
         | 
| 90 | 
            +
                      ))
         | 
| 91 | 
            +
                      raise(e)
         | 
| 92 | 
            +
                    end
         | 
| 93 | 
            +
                    log(data.merge(:at => :finish, :elapsed => Time.now - start))
         | 
| 94 | 
            +
                    res
         | 
| 95 | 
            +
                  end
         | 
| 96 | 
            +
                end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                def log_exception(data, e)
         | 
| 99 | 
            +
                  sync_stream(STDERR) unless @defined
         | 
| 100 | 
            +
                  log(data.merge(
         | 
| 101 | 
            +
                    :exception    => true,
         | 
| 102 | 
            +
                    :class        => e.class,
         | 
| 103 | 
            +
                    :message      => e.message,
         | 
| 104 | 
            +
                    :exception_id => e.object_id.abs
         | 
| 105 | 
            +
                  ))
         | 
| 106 | 
            +
                  if e.backtrace
         | 
| 107 | 
            +
                    bt = e.backtrace.reverse
         | 
| 108 | 
            +
                    bt[0, bt.size-6].each do |line|
         | 
| 109 | 
            +
                      log(data.merge(
         | 
| 110 | 
            +
                        :exception    => true,
         | 
| 111 | 
            +
                        :exception_id => e.object_id.abs,
         | 
| 112 | 
            +
                        :site         => line.gsub(/[`'"]/, "")
         | 
| 113 | 
            +
                      ))
         | 
| 114 | 
            +
                    end
         | 
| 115 | 
            +
                  end
         | 
| 116 | 
            +
                end
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                def log_level_ok?(level)
         | 
| 119 | 
            +
                  if level
         | 
| 120 | 
            +
                    LOG_LEVEL_MAP[level.to_s] <= LOG_LEVEL
         | 
| 121 | 
            +
                  else
         | 
| 122 | 
            +
                    true
         | 
| 123 | 
            +
                  end
         | 
| 124 | 
            +
                end
         | 
| 125 | 
            +
             | 
| 126 | 
            +
              end
         | 
| 127 | 
            +
            end
         | 
    
        data/lib/queue_classic/worker.rb
    CHANGED
    
    | @@ -1,26 +1,37 @@ | |
| 1 1 | 
             
            module QC
         | 
| 2 2 | 
             
              class Worker
         | 
| 3 3 |  | 
| 4 | 
            -
                def initialize( | 
| 5 | 
            -
                   | 
| 6 | 
            -
             | 
| 4 | 
            +
                def initialize(*args)
         | 
| 5 | 
            +
                  if args.length == 5
         | 
| 6 | 
            +
                    q_name, top_bound, fork_worker, listening_worker, max_attempts = *args
         | 
| 7 | 
            +
                  elsif args.length <= 1
         | 
| 8 | 
            +
                    opts = args.first || {}
         | 
| 9 | 
            +
                    q_name           = opts[:q_name]           || QC::QUEUE
         | 
| 10 | 
            +
                    top_bound        = opts[:top_bound]        || QC::TOP_BOUND
         | 
| 11 | 
            +
                    fork_worker      = opts[:fork_worker]      || QC::FORK_WORKER
         | 
| 12 | 
            +
                    listening_worker = opts[:listening_worker] || QC::LISTENING_WORKER
         | 
| 13 | 
            +
                    max_attempts     = opts[:max_attempts]     || QC::MAX_LOCK_ATTEMPTS
         | 
| 14 | 
            +
                  else
         | 
| 15 | 
            +
                    raise ArgumentError, 'wrong number of arguments (expected no args, an options hash, or 5 separate args)'
         | 
| 16 | 
            +
                  end
         | 
| 7 17 |  | 
| 18 | 
            +
                  @running = true
         | 
| 8 19 | 
             
                  @queue = Queue.new(q_name, listening_worker)
         | 
| 9 | 
            -
                  log("worker queue=#{@queue.name}")
         | 
| 10 | 
            -
             | 
| 11 20 | 
             
                  @top_bound = top_bound
         | 
| 12 | 
            -
                  log("worker top_bound=#{@top_bound}")
         | 
| 13 | 
            -
             | 
| 14 21 | 
             
                  @fork_worker = fork_worker
         | 
| 15 | 
            -
                  log("worker fork=#{@fork_worker}")
         | 
| 16 | 
            -
             | 
| 17 22 | 
             
                  @listening_worker = listening_worker
         | 
| 18 | 
            -
                  log("worker listen=#{@listening_worker}")
         | 
| 19 | 
            -
             | 
| 20 23 | 
             
                  @max_attempts = max_attempts
         | 
| 21 | 
            -
                  log("max lock attempts =#{@max_attempts}")
         | 
| 22 | 
            -
             | 
| 23 24 | 
             
                  handle_signals
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  log(
         | 
| 27 | 
            +
                    :level => :debug,
         | 
| 28 | 
            +
                    :action => "worker_initialized",
         | 
| 29 | 
            +
                    :queue => q_name,
         | 
| 30 | 
            +
                    :top_bound => top_bound,
         | 
| 31 | 
            +
                    :fork_worker => fork_worker,
         | 
| 32 | 
            +
                    :listening_worker => listening_worker,
         | 
| 33 | 
            +
                    :max_attempts => max_attempts
         | 
| 34 | 
            +
                  )
         | 
| 24 35 | 
             
                end
         | 
| 25 36 |  | 
| 26 37 | 
             
                def running?
         | 
| @@ -40,7 +51,7 @@ module QC | |
| 40 51 | 
             
                    trap(sig) do
         | 
| 41 52 | 
             
                      if running?
         | 
| 42 53 | 
             
                        @running = false
         | 
| 43 | 
            -
                        log(" | 
| 54 | 
            +
                        log(:level => :debug, :action => "handle_signal", :running => @running)
         | 
| 44 55 | 
             
                      else
         | 
| 45 56 | 
             
                        raise Interrupt
         | 
| 46 57 | 
             
                      end
         | 
| @@ -52,13 +63,10 @@ module QC | |
| 52 63 | 
             
                # your worker is forking and you need to
         | 
| 53 64 | 
             
                # re-establish database connectoins
         | 
| 54 65 | 
             
                def setup_child
         | 
| 55 | 
            -
                  log("forked worker running setup")
         | 
| 56 66 | 
             
                end
         | 
| 57 67 |  | 
| 58 68 | 
             
                def start
         | 
| 59 | 
            -
                  log("worker starting")
         | 
| 60 69 | 
             
                  while running?
         | 
| 61 | 
            -
                    log("worker running...")
         | 
| 62 70 | 
             
                    if fork_worker?
         | 
| 63 71 | 
             
                      fork_and_work
         | 
| 64 72 | 
             
                    else
         | 
| @@ -69,48 +77,44 @@ module QC | |
| 69 77 |  | 
| 70 78 | 
             
                def fork_and_work
         | 
| 71 79 | 
             
                  @cpid = fork { setup_child; work }
         | 
| 72 | 
            -
                  log( | 
| 80 | 
            +
                  log(:level => :debug, :action => :fork, :pid => @cpid)
         | 
| 73 81 | 
             
                  Process.wait(@cpid)
         | 
| 74 82 | 
             
                end
         | 
| 75 83 |  | 
| 76 84 | 
             
                def work
         | 
| 77 | 
            -
                  log("worker start working")
         | 
| 78 85 | 
             
                  if job = lock_job
         | 
| 79 | 
            -
                     | 
| 80 | 
            -
             | 
| 81 | 
            -
             | 
| 82 | 
            -
             | 
| 86 | 
            +
                    QC.log_yield(:level => :info, :action => "work_job", :job => job[:id]) do
         | 
| 87 | 
            +
                      begin
         | 
| 88 | 
            +
                        call(job)
         | 
| 89 | 
            +
                      rescue Object => e
         | 
| 90 | 
            +
                        log(:level => :debug, :action => "failed_work", :job => job[:id], :error => e.inspect)
         | 
| 91 | 
            +
                        handle_failure(job, e)
         | 
| 92 | 
            +
                      ensure
         | 
| 93 | 
            +
                        @queue.delete(job[:id])
         | 
| 94 | 
            +
                        log(:level => :debug, :action => "delete_job", :job => job[:id])
         | 
| 83 95 | 
             
                      end
         | 
| 84 | 
            -
                    rescue Object => e
         | 
| 85 | 
            -
                      log("worker failed job=#{job[:id]} exception=#{e.inspect}")
         | 
| 86 | 
            -
                      handle_failure(job, e)
         | 
| 87 | 
            -
                    ensure
         | 
| 88 | 
            -
                      @queue.delete(job[:id])
         | 
| 89 | 
            -
                      log("worker deleted job=#{job[:id]}")
         | 
| 90 96 | 
             
                    end
         | 
| 91 97 | 
             
                  end
         | 
| 92 98 | 
             
                end
         | 
| 93 99 |  | 
| 94 100 | 
             
                def lock_job
         | 
| 95 | 
            -
                  log( | 
| 101 | 
            +
                  log(:level => :debug, :action => "lock_job")
         | 
| 96 102 | 
             
                  attempts = 0
         | 
| 97 103 | 
             
                  job = nil
         | 
| 98 104 | 
             
                  until job
         | 
| 99 105 | 
             
                    job = @queue.lock(@top_bound)
         | 
| 100 106 | 
             
                    if job.nil?
         | 
| 101 | 
            -
                      log(" | 
| 107 | 
            +
                      log(:level => :debug, :action => "failed_lock", :attempts => attempts)
         | 
| 102 108 | 
             
                      if attempts < @max_attempts
         | 
| 103 109 | 
             
                        seconds = 2**attempts
         | 
| 104 110 | 
             
                        wait(seconds)
         | 
| 105 | 
            -
                        log("worker tries again")
         | 
| 106 111 | 
             
                        attempts += 1
         | 
| 107 112 | 
             
                        next
         | 
| 108 113 | 
             
                      else
         | 
| 109 | 
            -
                        log("worker reached max attempts. max=#{@max_attempts}")
         | 
| 110 114 | 
             
                        break
         | 
| 111 115 | 
             
                      end
         | 
| 112 116 | 
             
                    else
         | 
| 113 | 
            -
                      log(" | 
| 117 | 
            +
                      log(:level => :debug, :action => "finished_lock", :job => job[:id])
         | 
| 114 118 | 
             
                    end
         | 
| 115 119 | 
             
                  end
         | 
| 116 120 | 
             
                  job
         | 
| @@ -125,14 +129,14 @@ module QC | |
| 125 129 |  | 
| 126 130 | 
             
                def wait(t)
         | 
| 127 131 | 
             
                  if can_listen?
         | 
| 128 | 
            -
                    log(" | 
| 132 | 
            +
                    log(:level => :debug, :action => "listen_wait", :wait => t)
         | 
| 129 133 | 
             
                    Conn.listen(@queue.chan)
         | 
| 130 134 | 
             
                    Conn.wait_for_notify(t)
         | 
| 131 135 | 
             
                    Conn.unlisten(@queue.chan)
         | 
| 132 136 | 
             
                    Conn.drain_notify
         | 
| 133 | 
            -
                    log( | 
| 137 | 
            +
                    log(:level => :debug, :action => "finished_listening")
         | 
| 134 138 | 
             
                  else
         | 
| 135 | 
            -
                    log(" | 
| 139 | 
            +
                    log(:level => :debug, :action => "sleep_wait", :wait => t)
         | 
| 136 140 | 
             
                    Kernel.sleep(t)
         | 
| 137 141 | 
             
                  end
         | 
| 138 142 | 
             
                end
         | 
| @@ -146,8 +150,8 @@ module QC | |
| 146 150 | 
             
                  puts "!"
         | 
| 147 151 | 
             
                end
         | 
| 148 152 |  | 
| 149 | 
            -
                def log( | 
| 150 | 
            -
                   | 
| 153 | 
            +
                def log(data)
         | 
| 154 | 
            +
                  QC.log(data)
         | 
| 151 155 | 
             
                end
         | 
| 152 156 |  | 
| 153 157 | 
             
              end
         | 
    
        data/lib/queue_classic.rb
    CHANGED
    
    | @@ -1,10 +1,9 @@ | |
| 1 1 | 
             
            require "pg"
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            require "logger"
         | 
| 4 2 | 
             
            require "uri"
         | 
| 5 3 |  | 
| 6 4 | 
             
            $: << File.expand_path(__FILE__, "lib")
         | 
| 7 5 |  | 
| 6 | 
            +
            require "queue_classic/scrolls"
         | 
| 8 7 | 
             
            require "queue_classic/okjson"
         | 
| 9 8 | 
             
            require "queue_classic/conn"
         | 
| 10 9 | 
             
            require "queue_classic/queries"
         | 
| @@ -12,6 +11,8 @@ require "queue_classic/queue" | |
| 12 11 | 
             
            require "queue_classic/worker"
         | 
| 13 12 |  | 
| 14 13 | 
             
            module QC
         | 
| 14 | 
            +
              # ENV["QC_LOG_LEVEL"] is used in Scrolls
         | 
| 15 | 
            +
              Scrolls::Log.start
         | 
| 15 16 |  | 
| 16 17 | 
             
              Root = File.expand_path("..", File.dirname(__FILE__))
         | 
| 17 18 | 
             
              SqlFunctions = File.join(QC::Root, "/sql/ddl.sql")
         | 
| @@ -22,9 +23,6 @@ module QC | |
| 22 23 | 
             
                ENV["DATABASE_URL"]    ||
         | 
| 23 24 | 
             
                raise(ArgumentError, "missing QC_DATABASE_URL or DATABASE_URL")
         | 
| 24 25 |  | 
| 25 | 
            -
              # export QC_LOG_LEVEL=`ruby -r "logger" -e "puts Logger::ERROR"`
         | 
| 26 | 
            -
              LOG_LEVEL = (ENV["QC_LOG_LEVEL"] || Logger::DEBUG).to_i
         | 
| 27 | 
            -
             | 
| 28 26 | 
             
              # You can use the APP_NAME to query for
         | 
| 29 27 | 
             
              # postgres related process information in the
         | 
| 30 28 | 
             
              # pg_stat_activity table. Don't set this unless
         | 
| @@ -66,12 +64,6 @@ module QC | |
| 66 64 | 
             
              # as the max exponent.
         | 
| 67 65 | 
             
              MAX_LOCK_ATTEMPTS = (ENV["QC_MAX_LOCK_ATTEMPTS"] || 5).to_i
         | 
| 68 66 |  | 
| 69 | 
            -
             | 
| 70 | 
            -
              # Setup the logger
         | 
| 71 | 
            -
              Log = Logger.new($stdout)
         | 
| 72 | 
            -
              Log.level = LOG_LEVEL
         | 
| 73 | 
            -
              Log.info("program=queue_classic log=true")
         | 
| 74 | 
            -
             | 
| 75 67 | 
             
              # Defer method calls on the QC module to the
         | 
| 76 68 | 
             
              # default queue. This facilitates QC.enqueue()
         | 
| 77 69 | 
             
              def self.method_missing(sym, *args, &block)
         | 
| @@ -84,4 +76,21 @@ module QC | |
| 84 76 | 
             
                end
         | 
| 85 77 | 
             
              end
         | 
| 86 78 |  | 
| 79 | 
            +
              def self.log_yield(data)
         | 
| 80 | 
            +
                begin
         | 
| 81 | 
            +
                  t0 = Time.now
         | 
| 82 | 
            +
                  yield
         | 
| 83 | 
            +
                rescue => e
         | 
| 84 | 
            +
                  log({:level => :error, :error => e.class, :message => e.message.strip}.merge(data))
         | 
| 85 | 
            +
                  raise
         | 
| 86 | 
            +
                ensure
         | 
| 87 | 
            +
                  t = Integer((Time.now - t0)*1000)
         | 
| 88 | 
            +
                  log(data.merge(:elapsed => t)) unless e
         | 
| 89 | 
            +
                end
         | 
| 90 | 
            +
              end
         | 
| 91 | 
            +
             | 
| 92 | 
            +
              def self.log(data)
         | 
| 93 | 
            +
                Scrolls.log({:lib => :queue_classic}.merge(data))
         | 
| 94 | 
            +
              end
         | 
| 95 | 
            +
             | 
| 87 96 | 
             
            end
         | 
    
        data/readme.md
    CHANGED
    
    | @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            # queue_classic
         | 
| 2 2 |  | 
| 3 | 
            -
            v2.0. | 
| 3 | 
            +
            v2.0.0rc9
         | 
| 4 4 |  | 
| 5 5 | 
             
            queue_classic is a PostgreSQL-backed queueing library that is focused on
         | 
| 6 6 | 
             
            concurrent job locking, minimizing database load & providing a simple &
         | 
| @@ -14,6 +14,7 @@ queue_classic features: | |
| 14 14 | 
             
            * Forking workers
         | 
| 15 15 | 
             
            * Postgres' rock-solid locking mechanism
         | 
| 16 16 | 
             
            * Fuzzy-FIFO support [academic paper](http://www.cs.tau.ac.il/~shanir/nir-pubs-web/Papers/Lock_Free.pdf)
         | 
| 17 | 
            +
            * Instrumentation via log output
         | 
| 17 18 | 
             
            * Long term support
         | 
| 18 19 |  | 
| 19 20 | 
             
            ## Proven
         | 
| @@ -387,6 +388,17 @@ a method that you can override. This method will be passed 2 arguments: the | |
| 387 388 | 
             
            exception instance and the job. Here are a few examples of things you might want
         | 
| 388 389 | 
             
            to do inside `handle_failure()`.
         | 
| 389 390 |  | 
| 391 | 
            +
            ## Instrumentation
         | 
| 392 | 
            +
             | 
| 393 | 
            +
            QC will log elapsed time, errors and general usage in the form of data.
         | 
| 394 | 
            +
            To customize the output of the log data, override `QC.log` and `QC.log_yield`.
         | 
| 395 | 
            +
            By default, QC uses a simple wrapper around $stdout to put the log data in k=v
         | 
| 396 | 
            +
            format. For instance:
         | 
| 397 | 
            +
             | 
| 398 | 
            +
            ```
         | 
| 399 | 
            +
            lib=queue_classic level=info action=insert_job elapsed=16
         | 
| 400 | 
            +
            ```
         | 
| 401 | 
            +
             | 
| 390 402 | 
             
            ## Tips and Tricks
         | 
| 391 403 |  | 
| 392 404 | 
             
            ### Running Synchronously for tests
         | 
    
        data/test/helper.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: queue_classic
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 2.0. | 
| 4 | 
            +
              version: 2.0.0rc10
         | 
| 5 5 | 
             
              prerelease: 5
         | 
| 6 6 | 
             
            platform: ruby
         | 
| 7 7 | 
             
            authors:
         | 
| @@ -13,7 +13,7 @@ date: 2012-02-29 00:00:00.000000000Z | |
| 13 13 | 
             
            dependencies:
         | 
| 14 14 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 15 15 | 
             
              name: pg
         | 
| 16 | 
            -
              requirement: & | 
| 16 | 
            +
              requirement: &13897100 !ruby/object:Gem::Requirement
         | 
| 17 17 | 
             
                none: false
         | 
| 18 18 | 
             
                requirements:
         | 
| 19 19 | 
             
                - - ~>
         | 
| @@ -21,7 +21,7 @@ dependencies: | |
| 21 21 | 
             
                    version: 0.13.2
         | 
| 22 22 | 
             
              type: :runtime
         | 
| 23 23 | 
             
              prerelease: false
         | 
| 24 | 
            -
              version_requirements: * | 
| 24 | 
            +
              version_requirements: *13897100
         | 
| 25 25 | 
             
            description: queue_classic is a queueing library for Ruby apps. (Rails, Sinatra, Etc...)
         | 
| 26 26 | 
             
              queue_classic features asynchronous job polling, database maintained locks and no
         | 
| 27 27 | 
             
              ridiculous dependencies. As a matter of fact, queue_classic only requires pg.
         | 
| @@ -36,6 +36,7 @@ files: | |
| 36 36 | 
             
            - lib/queue_classic/conn.rb
         | 
| 37 37 | 
             
            - lib/queue_classic/okjson.rb
         | 
| 38 38 | 
             
            - lib/queue_classic/worker.rb
         | 
| 39 | 
            +
            - lib/queue_classic/scrolls.rb
         | 
| 39 40 | 
             
            - lib/queue_classic/queue.rb
         | 
| 40 41 | 
             
            - lib/queue_classic/tasks.rb
         | 
| 41 42 | 
             
            - lib/queue_classic/queries.rb
         |