que 0.5.0 → 0.6.0
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -1
- data/.travis.yml +1 -1
- data/CHANGELOG.md +21 -1
- data/Gemfile +5 -0
- data/README.md +7 -6
- data/docs/advanced_setup.md +14 -4
- data/docs/customizing_que.md +4 -4
- data/docs/error_handling.md +13 -1
- data/docs/managing_workers.md +2 -2
- data/docs/migrating.md +26 -0
- data/docs/multiple_queues.md +13 -0
- data/docs/shutting_down_safely.md +7 -0
- data/docs/writing_reliable_jobs.md +43 -0
- data/lib/generators/que/templates/add_que.rb +1 -1
- data/lib/que.rb +27 -41
- data/lib/que/adapters/base.rb +75 -4
- data/lib/que/job.rb +45 -28
- data/lib/que/migrations.rb +3 -2
- data/lib/que/migrations/{1-down.sql → 1/down.sql} +0 -0
- data/lib/que/migrations/{1-up.sql → 1/up.sql} +0 -0
- data/lib/que/migrations/{2-down.sql → 2/down.sql} +0 -0
- data/lib/que/migrations/{2-up.sql → 2/up.sql} +0 -0
- data/lib/que/migrations/3/down.sql +5 -0
- data/lib/que/migrations/3/up.sql +5 -0
- data/lib/que/sql.rb +24 -17
- data/lib/que/version.rb +1 -1
- data/lib/que/worker.rb +6 -5
- data/spec/adapters/active_record_spec.rb +6 -6
- data/spec/adapters/sequel_spec.rb +4 -4
- data/spec/gemfiles/Gemfile1 +18 -0
- data/spec/gemfiles/Gemfile2 +18 -0
- data/spec/support/helpers.rb +2 -1
- data/spec/support/shared_examples/adapter.rb +7 -3
- data/spec/support/shared_examples/multi_threaded_adapter.rb +2 -2
- data/spec/travis.rb +12 -4
- data/spec/unit/customization_spec.rb +148 -0
- data/spec/unit/{queue_spec.rb → enqueue_spec.rb} +115 -14
- data/spec/unit/logging_spec.rb +3 -2
- data/spec/unit/migrations_spec.rb +3 -2
- data/spec/unit/pool_spec.rb +30 -6
- data/spec/unit/run_spec.rb +12 -0
- data/spec/unit/states_spec.rb +29 -31
- data/spec/unit/stats_spec.rb +16 -14
- data/spec/unit/work_spec.rb +120 -25
- data/spec/unit/worker_spec.rb +55 -9
- data/tasks/safe_shutdown.rb +1 -1
- metadata +30 -17
    
        data/spec/unit/logging_spec.rb
    CHANGED
    
    | @@ -1,12 +1,13 @@ | |
| 1 1 | 
             
            require 'spec_helper'
         | 
| 2 2 |  | 
| 3 3 | 
             
            describe "Logging" do
         | 
| 4 | 
            -
              it "by default should record the library and thread id in JSON" do
         | 
| 4 | 
            +
              it "by default should record the library and hostname and thread id in JSON" do
         | 
| 5 5 | 
             
                Que.log :event => "blah", :source => 4
         | 
| 6 6 | 
             
                $logger.messages.count.should be 1
         | 
| 7 7 |  | 
| 8 8 | 
             
                message = JSON.load($logger.messages.first)
         | 
| 9 9 | 
             
                message['lib'].should == 'que'
         | 
| 10 | 
            +
                message['hostname'].should == Socket.gethostname
         | 
| 10 11 | 
             
                message['event'].should == 'blah'
         | 
| 11 12 | 
             
                message['source'].should == 4
         | 
| 12 13 | 
             
                message['thread'].should == Thread.current.object_id
         | 
| @@ -16,7 +17,7 @@ describe "Logging" do | |
| 16 17 | 
             
                begin
         | 
| 17 18 | 
             
                  Que.logger = nil
         | 
| 18 19 |  | 
| 19 | 
            -
                  Que::Job. | 
| 20 | 
            +
                  Que::Job.enqueue
         | 
| 20 21 | 
             
                  worker = Que::Worker.new
         | 
| 21 22 | 
             
                  sleep_until { worker.sleeping? }
         | 
| 22 23 |  | 
| @@ -7,7 +7,7 @@ describe Que::Migrations do | |
| 7 7 |  | 
| 8 8 | 
             
                default = proc do
         | 
| 9 9 | 
             
                  result = Que.execute <<-SQL
         | 
| 10 | 
            -
                    select adsrc
         | 
| 10 | 
            +
                    select adsrc::integer
         | 
| 11 11 | 
             
                    from pg_attribute a
         | 
| 12 12 | 
             
                    join pg_class c on c.oid = a.attrelid
         | 
| 13 13 | 
             
                    join pg_attrdef on adrelid = attrelid AND adnum = attnum
         | 
| @@ -15,7 +15,7 @@ describe Que::Migrations do | |
| 15 15 | 
             
                    and attname = 'priority'
         | 
| 16 16 | 
             
                  SQL
         | 
| 17 17 |  | 
| 18 | 
            -
                  result.first[ | 
| 18 | 
            +
                  result.first[:adsrc]
         | 
| 19 19 | 
             
                end
         | 
| 20 20 |  | 
| 21 21 | 
             
                default.call.should == 100
         | 
| @@ -40,6 +40,7 @@ describe Que::Migrations do | |
| 40 40 | 
             
                Que::Migrations.db_version.should == Que::Migrations::CURRENT_VERSION
         | 
| 41 41 | 
             
                Que::Migrations.migrate! :version => 0
         | 
| 42 42 | 
             
                Que::Migrations.db_version.should == 0
         | 
| 43 | 
            +
                Que.db_version.should == 0
         | 
| 43 44 | 
             
                Que::Migrations.migrate!
         | 
| 44 45 | 
             
                Que::Migrations.db_version.should == Que::Migrations::CURRENT_VERSION
         | 
| 45 46 |  | 
    
        data/spec/unit/pool_spec.rb
    CHANGED
    
    | @@ -19,15 +19,15 @@ describe "Managing the Worker pool" do | |
| 19 19 | 
             
                it "should make jobs run in the same thread as they are queued" do
         | 
| 20 20 | 
             
                  Que.mode = :sync
         | 
| 21 21 |  | 
| 22 | 
            -
                  ArgsJob. | 
| 23 | 
            -
                  $passed_args.should == [5, { | 
| 22 | 
            +
                  ArgsJob.enqueue(5, :testing => "synchronous").should be_an_instance_of ArgsJob
         | 
| 23 | 
            +
                  $passed_args.should == [5, {:testing => "synchronous"}]
         | 
| 24 24 | 
             
                  DB[:que_jobs].count.should be 0
         | 
| 25 25 | 
             
                end
         | 
| 26 26 |  | 
| 27 27 | 
             
                it "should not affect jobs that are queued with specific run_ats" do
         | 
| 28 28 | 
             
                  Que.mode = :sync
         | 
| 29 29 |  | 
| 30 | 
            -
                  ArgsJob. | 
| 30 | 
            +
                  ArgsJob.enqueue(5, :testing => "synchronous", :run_at => Time.now + 60)
         | 
| 31 31 | 
             
                  DB[:que_jobs].select_map(:job_class).should == ["ArgsJob"]
         | 
| 32 32 | 
             
                end
         | 
| 33 33 | 
             
              end
         | 
| @@ -132,7 +132,7 @@ describe "Managing the Worker pool" do | |
| 132 132 | 
             
                  Que.mode = :async
         | 
| 133 133 | 
             
                  sleep_until { Que::Worker.workers.all? &:sleeping? }
         | 
| 134 134 |  | 
| 135 | 
            -
                  BlockJob. | 
| 135 | 
            +
                  BlockJob.enqueue
         | 
| 136 136 | 
             
                  Que.wake!
         | 
| 137 137 |  | 
| 138 138 | 
             
                  $q1.pop
         | 
| @@ -158,7 +158,7 @@ describe "Managing the Worker pool" do | |
| 158 158 | 
             
                  Que.mode = :async
         | 
| 159 159 | 
             
                  sleep_until { Que::Worker.workers.all? &:sleeping? }
         | 
| 160 160 |  | 
| 161 | 
            -
                  4.times { BlockJob. | 
| 161 | 
            +
                  4.times { BlockJob.enqueue }
         | 
| 162 162 | 
             
                  Que.wake_all!
         | 
| 163 163 | 
             
                  4.times { $q1.pop }
         | 
| 164 164 |  | 
| @@ -179,8 +179,32 @@ describe "Managing the Worker pool" do | |
| 179 179 | 
             
                  Que.mode = :async
         | 
| 180 180 | 
             
                  sleep_until { Que::Worker.workers.all? &:sleeping? }
         | 
| 181 181 | 
             
                  Que.wake_interval = 0.01 # 10 ms
         | 
| 182 | 
            -
                  Que::Job. | 
| 182 | 
            +
                  Que::Job.enqueue
         | 
| 183 183 | 
             
                  sleep_until { DB[:que_jobs].count == 0 }
         | 
| 184 184 | 
             
                end
         | 
| 185 | 
            +
             | 
| 186 | 
            +
                it "should work jobs in the queue defined by QUE_QUEUE" do
         | 
| 187 | 
            +
                  begin
         | 
| 188 | 
            +
                    Que::Job.enqueue 1
         | 
| 189 | 
            +
                    Que::Job.enqueue 2, :queue => 'my_queue'
         | 
| 190 | 
            +
             | 
| 191 | 
            +
                    ENV['QUE_QUEUE'] = 'my_queue'
         | 
| 192 | 
            +
             | 
| 193 | 
            +
                    Que.mode = :async
         | 
| 194 | 
            +
                    sleep_until { Que::Worker.workers.all? &:sleeping? }
         | 
| 195 | 
            +
                    DB[:que_jobs].count.should be 1
         | 
| 196 | 
            +
             | 
| 197 | 
            +
                    job = DB[:que_jobs].first
         | 
| 198 | 
            +
                    job[:queue].should == ''
         | 
| 199 | 
            +
                    job[:args].should == '[1]'
         | 
| 200 | 
            +
                  ensure
         | 
| 201 | 
            +
                    ENV.delete('QUE_QUEUE')
         | 
| 202 | 
            +
             | 
| 203 | 
            +
                    if @worker
         | 
| 204 | 
            +
                      @worker.stop
         | 
| 205 | 
            +
                      @worker.wait_until_stopped
         | 
| 206 | 
            +
                    end
         | 
| 207 | 
            +
                  end
         | 
| 208 | 
            +
                end
         | 
| 185 209 | 
             
              end
         | 
| 186 210 | 
             
            end
         | 
| @@ -0,0 +1,12 @@ | |
| 1 | 
            +
            require 'spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe Que::Job, '.run' do
         | 
| 4 | 
            +
              it "should immediately process the job with the arguments given to it" do
         | 
| 5 | 
            +
                result = ArgsJob.run 1, 'two', {:three => 3}
         | 
| 6 | 
            +
                result.should be_an_instance_of ArgsJob
         | 
| 7 | 
            +
                result.attrs[:args].should == [1, 'two', {:three => 3}]
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                DB[:que_jobs].count.should be 0
         | 
| 10 | 
            +
                $passed_args.should == [1, 'two', {:three => 3}]
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
            end
         | 
    
        data/spec/unit/states_spec.rb
    CHANGED
    
    | @@ -6,45 +6,43 @@ describe Que, '.worker_states' do | |
| 6 6 |  | 
| 7 7 | 
             
                class WorkerStateJob < BlockJob
         | 
| 8 8 | 
             
                  def run
         | 
| 9 | 
            -
                    $pid = Que.execute("select pg_backend_pid()").first[ | 
| 9 | 
            +
                    $pid = Que.execute("select pg_backend_pid()").first[:pg_backend_pid]
         | 
| 10 10 | 
             
                    super
         | 
| 11 11 | 
             
                  end
         | 
| 12 12 | 
             
                end
         | 
| 13 13 |  | 
| 14 | 
            -
                WorkerStateJob. | 
| 14 | 
            +
                WorkerStateJob.enqueue :priority => 2
         | 
| 15 15 |  | 
| 16 16 | 
             
                # Ensure that the portion of the SQL query that accounts for bigint
         | 
| 17 17 | 
             
                # job_ids functions correctly.
         | 
| 18 18 | 
             
                DB[:que_jobs].update(:job_id => 2**33)
         | 
| 19 19 |  | 
| 20 | 
            -
                 | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 44 | 
            -
             | 
| 45 | 
            -
             | 
| 46 | 
            -
             | 
| 47 | 
            -
                  state[:pg_waiting_on_lock].should == 'f'
         | 
| 48 | 
            -
                end
         | 
| 20 | 
            +
                t = Thread.new { Que::Job.work }
         | 
| 21 | 
            +
                $q1.pop
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                states = Que.worker_states
         | 
| 24 | 
            +
                states.length.should be 1
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                $q2.push nil
         | 
| 27 | 
            +
                t.join
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                state = states.first
         | 
| 30 | 
            +
                state.keys.should == %w(priority run_at job_id job_class args error_count last_error queue pg_backend_pid pg_state pg_state_changed_at pg_last_query pg_last_query_started_at pg_transaction_started_at pg_waiting_on_lock)
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                state[:priority].should == 2
         | 
| 33 | 
            +
                state[:run_at].should be_within(3).of Time.now
         | 
| 34 | 
            +
                state[:job_id].should == 2**33
         | 
| 35 | 
            +
                state[:job_class].should == 'WorkerStateJob'
         | 
| 36 | 
            +
                state[:args].should == []
         | 
| 37 | 
            +
                state[:error_count].should == 0
         | 
| 38 | 
            +
                state[:last_error].should be nil
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                state[:pg_backend_pid].should == $pid
         | 
| 41 | 
            +
                state[:pg_state].should == 'idle'
         | 
| 42 | 
            +
                state[:pg_state_changed_at].should be_within(3).of Time.now
         | 
| 43 | 
            +
                state[:pg_last_query].should == 'select pg_backend_pid()'
         | 
| 44 | 
            +
                state[:pg_last_query_started_at].should be_within(3).of Time.now
         | 
| 45 | 
            +
                state[:pg_transaction_started_at].should == nil
         | 
| 46 | 
            +
                state[:pg_waiting_on_lock].should == false
         | 
| 49 47 | 
             
              end if QUE_ADAPTERS[:connection_pool]
         | 
| 50 48 | 
             
            end
         | 
    
        data/spec/unit/stats_spec.rb
    CHANGED
    
    | @@ -2,15 +2,15 @@ require 'spec_helper' | |
| 2 2 |  | 
| 3 3 | 
             
            describe Que, '.job_stats' do
         | 
| 4 4 | 
             
              it "should return a list of the job types in the queue, their counts and the number of each currently running" do
         | 
| 5 | 
            -
                BlockJob. | 
| 6 | 
            -
                Que::Job. | 
| 5 | 
            +
                BlockJob.enqueue
         | 
| 6 | 
            +
                Que::Job.enqueue
         | 
| 7 7 |  | 
| 8 8 | 
             
                # Have to tweak the job_id to ensure that the portion of the SQL query
         | 
| 9 9 | 
             
                # that accounts for bigint job_ids functions correctly.
         | 
| 10 10 | 
             
                old = Time.now - 3600
         | 
| 11 11 | 
             
                DB[:que_jobs].where(:job_class => "Que::Job").update(:job_id => 2**33, :error_count => 5, :run_at => old)
         | 
| 12 12 |  | 
| 13 | 
            -
                Que::Job. | 
| 13 | 
            +
                Que::Job.enqueue
         | 
| 14 14 |  | 
| 15 15 | 
             
                begin
         | 
| 16 16 | 
             
                  DB.get{pg_advisory_lock(2**33)}
         | 
| @@ -20,21 +20,23 @@ describe Que, '.job_stats' do | |
| 20 20 |  | 
| 21 21 | 
             
                  qj, bj = stats
         | 
| 22 22 |  | 
| 23 | 
            -
                  qj.keys.should == %w(job_class count count_working count_errored highest_error_count oldest_run_at)
         | 
| 23 | 
            +
                  qj.keys.should == %w(queue job_class count count_working count_errored highest_error_count oldest_run_at)
         | 
| 24 24 |  | 
| 25 | 
            +
                  qj[:queue].should == ''
         | 
| 25 26 | 
             
                  qj[:job_class].should == 'Que::Job'
         | 
| 26 | 
            -
                  qj[:count].should ==  | 
| 27 | 
            -
                  qj[:count_working].should ==  | 
| 28 | 
            -
                  qj[:count_errored].should ==  | 
| 29 | 
            -
                  qj[:highest_error_count].should ==  | 
| 30 | 
            -
                   | 
| 27 | 
            +
                  qj[:count].should == 2
         | 
| 28 | 
            +
                  qj[:count_working].should == 1
         | 
| 29 | 
            +
                  qj[:count_errored].should == 1
         | 
| 30 | 
            +
                  qj[:highest_error_count].should == 5
         | 
| 31 | 
            +
                  qj[:oldest_run_at].should be_within(3).of old
         | 
| 31 32 |  | 
| 33 | 
            +
                  bj[:queue].should == ''
         | 
| 32 34 | 
             
                  bj[:job_class].should == 'BlockJob'
         | 
| 33 | 
            -
                  bj[:count].should ==  | 
| 34 | 
            -
                  bj[:count_working].should ==  | 
| 35 | 
            -
                  bj[:count_errored].should ==  | 
| 36 | 
            -
                  bj[:highest_error_count].should ==  | 
| 37 | 
            -
                   | 
| 35 | 
            +
                  bj[:count].should == 1
         | 
| 36 | 
            +
                  bj[:count_working].should == 0
         | 
| 37 | 
            +
                  bj[:count_errored].should == 0
         | 
| 38 | 
            +
                  bj[:highest_error_count].should == 0
         | 
| 39 | 
            +
                  bj[:oldest_run_at].should be_within(3).of Time.now
         | 
| 38 40 | 
             
                ensure
         | 
| 39 41 | 
             
                  DB.get{pg_advisory_unlock_all{}}
         | 
| 40 42 | 
             
                end
         | 
    
        data/spec/unit/work_spec.rb
    CHANGED
    
    | @@ -2,7 +2,7 @@ require 'spec_helper' | |
| 2 2 |  | 
| 3 3 | 
             
            describe Que::Job, '.work' do
         | 
| 4 4 | 
             
              it "should pass a job's arguments to the run method and delete it from the database" do
         | 
| 5 | 
            -
                ArgsJob. | 
| 5 | 
            +
                ArgsJob.enqueue 1, 'two', {'three' => 3}
         | 
| 6 6 | 
             
                DB[:que_jobs].count.should be 1
         | 
| 7 7 |  | 
| 8 8 | 
             
                result = Que::Job.work
         | 
| @@ -13,9 +13,38 @@ describe Que::Job, '.work' do | |
| 13 13 | 
             
                $passed_args.should == [1, 'two', {'three' => 3}]
         | 
| 14 14 | 
             
              end
         | 
| 15 15 |  | 
| 16 | 
            +
              it "should default to only working jobs without a named queue" do
         | 
| 17 | 
            +
                Que::Job.enqueue 1, :queue => 'other_queue'
         | 
| 18 | 
            +
                Que::Job.enqueue 2
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                result = Que::Job.work
         | 
| 21 | 
            +
                result[:event].should == :job_worked
         | 
| 22 | 
            +
                result[:job][:args].should == [2]
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                result = Que::Job.work
         | 
| 25 | 
            +
                result[:event].should == :job_unavailable
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              it "should accept the name of a single queue to pull jobs from" do
         | 
| 29 | 
            +
                Que::Job.enqueue 1, :queue => 'other_queue'
         | 
| 30 | 
            +
                Que::Job.enqueue 2, :queue => 'other_queue'
         | 
| 31 | 
            +
                Que::Job.enqueue 3
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                result = Que::Job.work(:other_queue)
         | 
| 34 | 
            +
                result[:event].should == :job_worked
         | 
| 35 | 
            +
                result[:job][:args].should == [1]
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                result = Que::Job.work('other_queue')
         | 
| 38 | 
            +
                result[:event].should == :job_worked
         | 
| 39 | 
            +
                result[:job][:args].should == [2]
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                result = Que::Job.work(:other_queue)
         | 
| 42 | 
            +
                result[:event].should == :job_unavailable
         | 
| 43 | 
            +
              end
         | 
| 44 | 
            +
             | 
| 16 45 | 
             
              it "should make a job's argument hashes indifferently accessible" do
         | 
| 17 46 | 
             
                DB[:que_jobs].count.should be 0
         | 
| 18 | 
            -
                ArgsJob. | 
| 47 | 
            +
                ArgsJob.enqueue 1, 'two', {'array' => [{'number' => 3}]}
         | 
| 19 48 | 
             
                DB[:que_jobs].count.should be 1
         | 
| 20 49 |  | 
| 21 50 | 
             
                result = Que::Job.work
         | 
| @@ -33,7 +62,7 @@ describe Que::Job, '.work' do | |
| 33 62 |  | 
| 34 63 | 
             
              it "should prefer a job with a higher priority" do
         | 
| 35 64 | 
             
                # 1 is highest priority.
         | 
| 36 | 
            -
                [5, 4, 3, 2, 1, 2, 3, 4, 5].map{|p| Que::Job. | 
| 65 | 
            +
                [5, 4, 3, 2, 1, 2, 3, 4, 5].map{|p| Que::Job.enqueue :priority => p}
         | 
| 37 66 | 
             
                DB[:que_jobs].order(:job_id).select_map(:priority).should == [5, 4, 3, 2, 1, 2, 3, 4, 5]
         | 
| 38 67 |  | 
| 39 68 | 
             
                result = Que::Job.work
         | 
| @@ -43,9 +72,9 @@ describe Que::Job, '.work' do | |
| 43 72 | 
             
              end
         | 
| 44 73 |  | 
| 45 74 | 
             
              it "should prefer a job that was scheduled to run longer ago when priorities are equal" do
         | 
| 46 | 
            -
                Que::Job. | 
| 47 | 
            -
                Que::Job. | 
| 48 | 
            -
                Que::Job. | 
| 75 | 
            +
                Que::Job.enqueue :run_at => Time.now - 30
         | 
| 76 | 
            +
                Que::Job.enqueue :run_at => Time.now - 60
         | 
| 77 | 
            +
                Que::Job.enqueue :run_at => Time.now - 30
         | 
| 49 78 |  | 
| 50 79 | 
             
                recent1, old, recent2 = DB[:que_jobs].order(:job_id).select_map(:run_at)
         | 
| 51 80 |  | 
| @@ -57,9 +86,9 @@ describe Que::Job, '.work' do | |
| 57 86 |  | 
| 58 87 | 
             
              it "should prefer a job that was queued earlier when priorities and run_ats are equal" do
         | 
| 59 88 | 
             
                run_at = Time.now - 30
         | 
| 60 | 
            -
                Que::Job. | 
| 61 | 
            -
                Que::Job. | 
| 62 | 
            -
                Que::Job. | 
| 89 | 
            +
                Que::Job.enqueue :run_at => run_at
         | 
| 90 | 
            +
                Que::Job.enqueue :run_at => run_at
         | 
| 91 | 
            +
                Que::Job.enqueue :run_at => run_at
         | 
| 63 92 |  | 
| 64 93 | 
             
                first, second, third = DB[:que_jobs].select_order_map(:job_id)
         | 
| 65 94 |  | 
| @@ -70,9 +99,9 @@ describe Que::Job, '.work' do | |
| 70 99 | 
             
              end
         | 
| 71 100 |  | 
| 72 101 | 
             
              it "should only work a job whose scheduled time to run has passed" do
         | 
| 73 | 
            -
                Que::Job. | 
| 74 | 
            -
                Que::Job. | 
| 75 | 
            -
                Que::Job. | 
| 102 | 
            +
                Que::Job.enqueue :run_at => Time.now + 30
         | 
| 103 | 
            +
                Que::Job.enqueue :run_at => Time.now - 30
         | 
| 104 | 
            +
                Que::Job.enqueue :run_at => Time.now + 30
         | 
| 76 105 |  | 
| 77 106 | 
             
                future1, past, future2 = DB[:que_jobs].order(:job_id).select_map(:run_at)
         | 
| 78 107 |  | 
| @@ -84,7 +113,7 @@ describe Que::Job, '.work' do | |
| 84 113 | 
             
              end
         | 
| 85 114 |  | 
| 86 115 | 
             
              it "should lock the job it selects" do
         | 
| 87 | 
            -
                BlockJob. | 
| 116 | 
            +
                BlockJob.enqueue
         | 
| 88 117 | 
             
                id = DB[:que_jobs].get(:job_id)
         | 
| 89 118 | 
             
                thread = Thread.new { Que::Job.work }
         | 
| 90 119 |  | 
| @@ -96,9 +125,9 @@ describe Que::Job, '.work' do | |
| 96 125 | 
             
              end
         | 
| 97 126 |  | 
| 98 127 | 
             
              it "should skip jobs that are advisory-locked" do
         | 
| 99 | 
            -
                Que::Job. | 
| 100 | 
            -
                Que::Job. | 
| 101 | 
            -
                Que::Job. | 
| 128 | 
            +
                Que::Job.enqueue :priority => 2
         | 
| 129 | 
            +
                Que::Job.enqueue :priority => 1
         | 
| 130 | 
            +
                Que::Job.enqueue :priority => 3
         | 
| 102 131 | 
             
                id = DB[:que_jobs].where(:priority => 1).get(:job_id)
         | 
| 103 132 |  | 
| 104 133 | 
             
                begin
         | 
| @@ -116,7 +145,7 @@ describe Que::Job, '.work' do | |
| 116 145 |  | 
| 117 146 | 
             
              it "should handle subclasses of other jobs" do
         | 
| 118 147 | 
             
                class SubClassJob < Que::Job
         | 
| 119 | 
            -
                  @ | 
| 148 | 
            +
                  @priority = 2
         | 
| 120 149 |  | 
| 121 150 | 
             
                  def run
         | 
| 122 151 | 
             
                    $job_spec_result << :sub
         | 
| @@ -124,7 +153,7 @@ describe Que::Job, '.work' do | |
| 124 153 | 
             
                end
         | 
| 125 154 |  | 
| 126 155 | 
             
                class SubSubClassJob < SubClassJob
         | 
| 127 | 
            -
                  @ | 
| 156 | 
            +
                  @priority = 4
         | 
| 128 157 |  | 
| 129 158 | 
             
                  def run
         | 
| 130 159 | 
             
                    super
         | 
| @@ -133,7 +162,7 @@ describe Que::Job, '.work' do | |
| 133 162 | 
             
                end
         | 
| 134 163 |  | 
| 135 164 | 
             
                $job_spec_result = []
         | 
| 136 | 
            -
                SubClassJob. | 
| 165 | 
            +
                SubClassJob.enqueue
         | 
| 137 166 | 
             
                DB[:que_jobs].select_map(:priority).should == [2]
         | 
| 138 167 | 
             
                result = Que::Job.work
         | 
| 139 168 | 
             
                result[:event].should == :job_worked
         | 
| @@ -141,7 +170,7 @@ describe Que::Job, '.work' do | |
| 141 170 | 
             
                $job_spec_result.should == [:sub]
         | 
| 142 171 |  | 
| 143 172 | 
             
                $job_spec_result = []
         | 
| 144 | 
            -
                SubSubClassJob. | 
| 173 | 
            +
                SubSubClassJob.enqueue
         | 
| 145 174 | 
             
                DB[:que_jobs].select_map(:priority).should == [4]
         | 
| 146 175 | 
             
                result = Que::Job.work
         | 
| 147 176 | 
             
                result[:event].should == :job_worked
         | 
| @@ -155,7 +184,7 @@ describe Que::Job, '.work' do | |
| 155 184 | 
             
                  end
         | 
| 156 185 | 
             
                end
         | 
| 157 186 |  | 
| 158 | 
            -
                ModuleJobModule::ModuleJob. | 
| 187 | 
            +
                ModuleJobModule::ModuleJob.enqueue
         | 
| 159 188 | 
             
                DB[:que_jobs].get(:job_class).should == "ModuleJobModule::ModuleJob"
         | 
| 160 189 |  | 
| 161 190 | 
             
                result = Que::Job.work
         | 
| @@ -170,7 +199,7 @@ describe Que::Job, '.work' do | |
| 170 199 | 
             
                  end
         | 
| 171 200 | 
             
                end
         | 
| 172 201 |  | 
| 173 | 
            -
                DestroyJob. | 
| 202 | 
            +
                DestroyJob.enqueue
         | 
| 174 203 | 
             
                DB[:que_jobs].count.should be 1
         | 
| 175 204 | 
             
                Que::Job.work
         | 
| 176 205 | 
             
                DB[:que_jobs].count.should be 0
         | 
| @@ -178,7 +207,7 @@ describe Que::Job, '.work' do | |
| 178 207 |  | 
| 179 208 | 
             
              describe "when encountering an error" do
         | 
| 180 209 | 
             
                it "should exponentially back off the job" do
         | 
| 181 | 
            -
                  ErrorJob. | 
| 210 | 
            +
                  ErrorJob.enqueue
         | 
| 182 211 |  | 
| 183 212 | 
             
                  result = Que::Job.work
         | 
| 184 213 | 
             
                  result[:event].should == :job_errored
         | 
| @@ -206,12 +235,78 @@ describe Que::Job, '.work' do | |
| 206 235 | 
             
                  job[:run_at].should be_within(3).of Time.now + 1299
         | 
| 207 236 | 
             
                end
         | 
| 208 237 |  | 
| 238 | 
            +
                it "should respect a custom retry interval" do
         | 
| 239 | 
            +
                  class RetryIntervalJob < ErrorJob
         | 
| 240 | 
            +
                    @retry_interval = 5
         | 
| 241 | 
            +
                  end
         | 
| 242 | 
            +
             | 
| 243 | 
            +
                  RetryIntervalJob.enqueue
         | 
| 244 | 
            +
             | 
| 245 | 
            +
                  result = Que::Job.work
         | 
| 246 | 
            +
                  result[:event].should == :job_errored
         | 
| 247 | 
            +
                  result[:error].should be_an_instance_of RuntimeError
         | 
| 248 | 
            +
                  result[:job][:job_class].should == 'RetryIntervalJob'
         | 
| 249 | 
            +
             | 
| 250 | 
            +
                  DB[:que_jobs].count.should be 1
         | 
| 251 | 
            +
                  job = DB[:que_jobs].first
         | 
| 252 | 
            +
                  job[:error_count].should be 1
         | 
| 253 | 
            +
                  job[:last_error].should =~ /\AErrorJob!\n/
         | 
| 254 | 
            +
                  job[:run_at].should be_within(3).of Time.now + 5
         | 
| 255 | 
            +
             | 
| 256 | 
            +
                  DB[:que_jobs].update :error_count => 5,
         | 
| 257 | 
            +
                                       :run_at => Time.now - 60
         | 
| 258 | 
            +
             | 
| 259 | 
            +
                  result = Que::Job.work
         | 
| 260 | 
            +
                  result[:event].should == :job_errored
         | 
| 261 | 
            +
                  result[:error].should be_an_instance_of RuntimeError
         | 
| 262 | 
            +
                  result[:job][:job_class].should == 'RetryIntervalJob'
         | 
| 263 | 
            +
             | 
| 264 | 
            +
                  DB[:que_jobs].count.should be 1
         | 
| 265 | 
            +
                  job = DB[:que_jobs].first
         | 
| 266 | 
            +
                  job[:error_count].should be 6
         | 
| 267 | 
            +
                  job[:last_error].should =~ /\AErrorJob!\n/
         | 
| 268 | 
            +
                  job[:run_at].should be_within(3).of Time.now + 5
         | 
| 269 | 
            +
                end
         | 
| 270 | 
            +
             | 
| 271 | 
            +
                it "should respect a custom retry interval formula" do
         | 
| 272 | 
            +
                  class RetryIntervalFormulaJob < ErrorJob
         | 
| 273 | 
            +
                    @retry_interval = proc { |count| count * 10 }
         | 
| 274 | 
            +
                  end
         | 
| 275 | 
            +
             | 
| 276 | 
            +
                  RetryIntervalFormulaJob.enqueue
         | 
| 277 | 
            +
             | 
| 278 | 
            +
                  result = Que::Job.work
         | 
| 279 | 
            +
                  result[:event].should == :job_errored
         | 
| 280 | 
            +
                  result[:error].should be_an_instance_of RuntimeError
         | 
| 281 | 
            +
                  result[:job][:job_class].should == 'RetryIntervalFormulaJob'
         | 
| 282 | 
            +
             | 
| 283 | 
            +
                  DB[:que_jobs].count.should be 1
         | 
| 284 | 
            +
                  job = DB[:que_jobs].first
         | 
| 285 | 
            +
                  job[:error_count].should be 1
         | 
| 286 | 
            +
                  job[:last_error].should =~ /\AErrorJob!\n/
         | 
| 287 | 
            +
                  job[:run_at].should be_within(3).of Time.now + 10
         | 
| 288 | 
            +
             | 
| 289 | 
            +
                  DB[:que_jobs].update :error_count => 5,
         | 
| 290 | 
            +
                                       :run_at => Time.now - 60
         | 
| 291 | 
            +
             | 
| 292 | 
            +
                  result = Que::Job.work
         | 
| 293 | 
            +
                  result[:event].should == :job_errored
         | 
| 294 | 
            +
                  result[:error].should be_an_instance_of RuntimeError
         | 
| 295 | 
            +
                  result[:job][:job_class].should == 'RetryIntervalFormulaJob'
         | 
| 296 | 
            +
             | 
| 297 | 
            +
                  DB[:que_jobs].count.should be 1
         | 
| 298 | 
            +
                  job = DB[:que_jobs].first
         | 
| 299 | 
            +
                  job[:error_count].should be 6
         | 
| 300 | 
            +
                  job[:last_error].should =~ /\AErrorJob!\n/
         | 
| 301 | 
            +
                  job[:run_at].should be_within(3).of Time.now + 60
         | 
| 302 | 
            +
                end
         | 
| 303 | 
            +
             | 
| 209 304 | 
             
                it "should pass it to an error handler, if one is defined" do
         | 
| 210 305 | 
             
                  begin
         | 
| 211 306 | 
             
                    errors = []
         | 
| 212 307 | 
             
                    Que.error_handler = proc { |error| errors << error }
         | 
| 213 308 |  | 
| 214 | 
            -
                    ErrorJob. | 
| 309 | 
            +
                    ErrorJob.enqueue
         | 
| 215 310 |  | 
| 216 311 | 
             
                    result = Que::Job.work
         | 
| 217 312 | 
             
                    result[:event].should == :job_errored
         | 
| @@ -230,7 +325,7 @@ describe Que::Job, '.work' do | |
| 230 325 | 
             
                it "should not do anything if the error handler itelf throws an error" do
         | 
| 231 326 | 
             
                  begin
         | 
| 232 327 | 
             
                    Que.error_handler = proc { |error| raise "Another error!" }
         | 
| 233 | 
            -
                    ErrorJob. | 
| 328 | 
            +
                    ErrorJob.enqueue
         | 
| 234 329 |  | 
| 235 330 | 
             
                    result = Que::Job.work
         | 
| 236 331 | 
             
                    result[:event].should == :job_errored
         |