sqewer 5.0.0 → 5.0.1
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/.travis.yml +1 -0
- data/ACTIVE_JOB.md +64 -0
- data/FAQ.md +0 -4
- data/Gemfile +4 -0
- data/README.md +4 -0
- data/Rakefile +1 -0
- data/bin/sqewer +7 -0
- data/bin/sqewer_rails +10 -0
- data/lib/sqewer.rb +18 -1
- data/lib/sqewer/atomic_counter.rb +2 -2
- data/lib/sqewer/cli.rb +3 -3
- data/lib/sqewer/connection.rb +16 -16
- data/lib/sqewer/connection_messagebox.rb +4 -4
- data/lib/sqewer/execution_context.rb +5 -5
- data/lib/sqewer/extensions/active_job_adapter.rb +78 -0
- data/lib/sqewer/{contrib → extensions}/appsignal_wrapper.rb +4 -4
- data/lib/sqewer/extensions/railtie.rb +12 -0
- data/lib/sqewer/middleware_stack.rb +7 -7
- data/lib/sqewer/null_logger.rb +1 -1
- data/lib/sqewer/resubmit.rb +17 -0
- data/lib/sqewer/serializer.rb +25 -25
- data/lib/sqewer/simple_job.rb +11 -11
- data/lib/sqewer/state_lock.rb +2 -2
- data/lib/sqewer/submitter.rb +17 -3
- data/lib/sqewer/version.rb +1 -1
- data/lib/sqewer/worker.rb +47 -47
- data/spec/spec_helper.rb +8 -2
- data/spec/sqewer/active_job_spec.rb +113 -0
- data/spec/sqewer/cli_spec.rb +48 -31
- data/spec/sqewer/serializer_spec.rb +51 -56
- data/spec/sqewer/submitter_spec.rb +18 -0
- data/spec/sqewer/worker_spec.rb +11 -9
- data/sqewer.gemspec +21 -5
- metadata +55 -5
- data/lib/sqewer/contrib/performable.rb +0 -23
    
        data/spec/spec_helper.rb
    CHANGED
    
    | @@ -15,12 +15,18 @@ RSpec.configure do |config| | |
| 15 15 | 
             
              config.order = 'random'
         | 
| 16 16 | 
             
              config.around :each do | example |
         | 
| 17 17 | 
             
                if example.metadata[:sqs]
         | 
| 18 | 
            -
                  queue_name = ' | 
| 18 | 
            +
                  queue_name = 'sqewer-test-queue-%s' % SecureRandom.hex(6)
         | 
| 19 19 | 
             
                  client = Aws::SQS::Client.new
         | 
| 20 20 | 
             
                  resp = client.create_queue(queue_name: queue_name)
         | 
| 21 21 | 
             
                  ENV['SQS_QUEUE_URL'] = resp.queue_url
         | 
| 22 | 
            +
                  
         | 
| 22 23 | 
             
                  example.run
         | 
| 23 | 
            -
                   | 
| 24 | 
            +
                  
         | 
| 25 | 
            +
                  # Sometimes the queue is already deleted before the example completes. If the test has passed,
         | 
| 26 | 
            +
                  # we do not really care whether this invocation raises an exception about a non-existent queue since
         | 
| 27 | 
            +
                  # all we care about is the queue _being gone_ at the end of the example.
         | 
| 28 | 
            +
                  client.delete_queue(queue_url: ENV.fetch('SQS_QUEUE_URL')) rescue Aws::SQS::Errors::NonExistentQueue
         | 
| 29 | 
            +
                  
         | 
| 24 30 | 
             
                  ENV.delete('SQS_QUEUE_URL')
         | 
| 25 31 | 
             
                else
         | 
| 26 32 | 
             
                  example.run
         | 
| @@ -0,0 +1,113 @@ | |
| 1 | 
            +
            require_relative '../spec_helper'
         | 
| 2 | 
            +
            require 'securerandom'
         | 
| 3 | 
            +
            require 'active_job'
         | 
| 4 | 
            +
            require 'active_record'
         | 
| 5 | 
            +
            require 'global_id'
         | 
| 6 | 
            +
            require_relative '../../lib/sqewer/extensions/active_job_adapter'
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            class CreateFileJob < ActiveJob::Base
         | 
| 9 | 
            +
              def perform(file)
         | 
| 10 | 
            +
                File.open(file, 'w') {}
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
            end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            class DeleteFileJob < ActiveJob::Base
         | 
| 15 | 
            +
              def perform(file)
         | 
| 16 | 
            +
                File.unlink(file)
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
            end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            class ActivateUser < ActiveJob::Base
         | 
| 21 | 
            +
              def perform(user)
         | 
| 22 | 
            +
                user.active = true
         | 
| 23 | 
            +
                user.save!
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
            end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            GlobalID.app = 'test-app'
         | 
| 28 | 
            +
            class User < ActiveRecord::Base
         | 
| 29 | 
            +
              include GlobalID::Identification
         | 
| 30 | 
            +
            end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
            describe ActiveJob::QueueAdapters::SqewerAdapter, :sqs => true do
         | 
| 33 | 
            +
              let(:file) { File.join(Dir.tmpdir, "file_active_job_test_1") }
         | 
| 34 | 
            +
              let(:client) { ::Aws::SQS::Client.new }
         | 
| 35 | 
            +
             | 
| 36 | 
            +
              after :all do
         | 
| 37 | 
            +
                # Ensure database files get killed afterwards
         | 
| 38 | 
            +
                File.unlink(ActiveRecord::Base.connection_config[:database]) rescue nil
         | 
| 39 | 
            +
              end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
              before :all do
         | 
| 42 | 
            +
                ActiveJob::Base.queue_adapter = ActiveJob::QueueAdapters::SqewerAdapter
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                test_seed_name = SecureRandom.hex(4)
         | 
| 45 | 
            +
                ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ('master_db_%s.sqlite3' % test_seed_name))
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                ActiveRecord::Migration.suppress_messages do
         | 
| 48 | 
            +
                  ActiveRecord::Schema.define(:version => 1) do
         | 
| 49 | 
            +
                    create_table :users do |t|
         | 
| 50 | 
            +
                      t.string :email, :null => true
         | 
| 51 | 
            +
                      t.boolean :active, default: false
         | 
| 52 | 
            +
                      t.timestamps :null => false
         | 
| 53 | 
            +
                    end
         | 
| 54 | 
            +
                  end
         | 
| 55 | 
            +
                end
         | 
| 56 | 
            +
              end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
              before do
         | 
| 59 | 
            +
                @queue_url_hash = { queue_url: ENV['SQS_QUEUE_URL'] }
         | 
| 60 | 
            +
              end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
              it "sends job to the queue" do
         | 
| 63 | 
            +
                CreateFileJob.perform_later(file)
         | 
| 64 | 
            +
                resp = client.get_queue_attributes(@queue_url_hash.merge(attribute_names: ["ApproximateNumberOfMessages"]))
         | 
| 65 | 
            +
                expect(resp.attributes["ApproximateNumberOfMessages"].to_i).to eq(1)
         | 
| 66 | 
            +
              end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
              it "correctly serializes the job into a Sqewer job" do
         | 
| 69 | 
            +
                job = CreateFileJob.perform_later(file)
         | 
| 70 | 
            +
                resp = client.receive_message(@queue_url_hash)
         | 
| 71 | 
            +
                serialized_job = JSON.parse(resp.messages.last.body)
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                expect(serialized_job["_job_class"]).to eq("ActiveJob::QueueAdapters::SqewerAdapter::Performable")
         | 
| 74 | 
            +
                expect(serialized_job["_job_params"]["job"]["job_id"]).to eq(job.job_id)
         | 
| 75 | 
            +
              end
         | 
| 76 | 
            +
             | 
| 77 | 
            +
              it "executes job from the queue" do
         | 
| 78 | 
            +
                file_delayed = "#{file}_delayed"
         | 
| 79 | 
            +
                CreateFileJob.perform_later(file)
         | 
| 80 | 
            +
                CreateFileJob.perform_later(file_delayed)
         | 
| 81 | 
            +
                w = Sqewer::Worker.default
         | 
| 82 | 
            +
                w.start
         | 
| 83 | 
            +
                begin
         | 
| 84 | 
            +
                  wait_for { File.exist?(file) }.to eq(true)
         | 
| 85 | 
            +
                  File.unlink(file)
         | 
| 86 | 
            +
                  
         | 
| 87 | 
            +
                  wait_for { File.exist?(file_delayed) }.to eq(true)
         | 
| 88 | 
            +
                  DeleteFileJob.set(wait: 5.seconds).perform_later(file_delayed)
         | 
| 89 | 
            +
                  
         | 
| 90 | 
            +
                  sleep 6
         | 
| 91 | 
            +
                  
         | 
| 92 | 
            +
                  expect(File.exist?(file_delayed)).to eq(false)
         | 
| 93 | 
            +
                ensure
         | 
| 94 | 
            +
                  w.stop
         | 
| 95 | 
            +
                end
         | 
| 96 | 
            +
              end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
              it "serializes and deserializes active record using GlobalID" do
         | 
| 99 | 
            +
                user = User.create(email: 'test@wetransfer.com')
         | 
| 100 | 
            +
                expect(user.active).to eq(false)
         | 
| 101 | 
            +
                ActivateUser.perform_later(user)
         | 
| 102 | 
            +
                w = Sqewer::Worker.default
         | 
| 103 | 
            +
                begin
         | 
| 104 | 
            +
                  w.start
         | 
| 105 | 
            +
                  sleep 4
         | 
| 106 | 
            +
                  user.reload
         | 
| 107 | 
            +
                  expect(user.active).to eq(true)
         | 
| 108 | 
            +
                ensure
         | 
| 109 | 
            +
                  w.stop
         | 
| 110 | 
            +
                end
         | 
| 111 | 
            +
              end
         | 
| 112 | 
            +
             | 
| 113 | 
            +
            end
         | 
    
        data/spec/sqewer/cli_spec.rb
    CHANGED
    
    | @@ -4,63 +4,80 @@ describe Sqewer::CLI, :sqs => true, :wait => {timeout: 120} do | |
| 4 4 | 
             
              after :each do
         | 
| 5 5 | 
             
                Dir.glob('*-result').each{|path| File.unlink(path) }
         | 
| 6 6 | 
             
              end
         | 
| 7 | 
            -
             | 
| 7 | 
            +
              
         | 
| 8 | 
            +
              describe 'with a mock Worker' do
         | 
| 9 | 
            +
                it 'uses just three methods' do
         | 
| 10 | 
            +
                  mock_worker = Class.new do
         | 
| 11 | 
            +
                    def self.start; end
         | 
| 12 | 
            +
                    def self.stop; end
         | 
| 13 | 
            +
                    def self.debug_thread_information!; end
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
                  
         | 
| 16 | 
            +
                  worker_pid = fork do
         | 
| 17 | 
            +
                    Sqewer::CLI.start(mock_worker)
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
                  sleep 1
         | 
| 20 | 
            +
                  
         | 
| 21 | 
            +
                  begin
         | 
| 22 | 
            +
                    Process.kill('INFO', worker_pid) # Calls debug_thread_information!
         | 
| 23 | 
            +
                  rescue ArgumentError, Errno::ENOTSUP # on Linux
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
                  Process.kill('TERM', worker_pid) # Terminates the worker
         | 
| 26 | 
            +
                  
         | 
| 27 | 
            +
                  wait_for { 
         | 
| 28 | 
            +
                    _, status = Process.wait2(worker_pid)
         | 
| 29 | 
            +
                    expect(status.exitstatus).to be_zero # Must have quit cleanly
         | 
| 30 | 
            +
                  }
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
              
         | 
| 8 34 | 
             
              describe 'runs the commandline app, executes jobs and then quits cleanly' do
         | 
| 9 35 | 
             
                it 'on a USR1 signal' do
         | 
| 10 36 | 
             
                  submitter = Sqewer::Connection.default
         | 
| 11 37 |  | 
| 12 | 
            -
                   | 
| 13 | 
            -
             | 
| 14 | 
            -
                  
         | 
| 15 | 
            -
                  pid = fork { $stderr.reopen(stderr); $stderr.sync = true; exec("ruby #{__dir__}/cli_app.rb") }
         | 
| 16 | 
            -
              
         | 
| 38 | 
            +
                  pid = fork { exec("ruby #{__dir__}/cli_app.rb") }
         | 
| 39 | 
            +
             | 
| 17 40 | 
             
                  Thread.new do
         | 
| 18 41 | 
             
                    20.times do
         | 
| 19 | 
            -
                      j = { | 
| 42 | 
            +
                      j = {"_job_class" => 'MyJob', "_job_params" => {first_name: 'John', last_name: 'Doe'}}
         | 
| 20 43 | 
             
                      submitter.send_message(JSON.dump(j))
         | 
| 21 44 | 
             
                    end
         | 
| 22 45 | 
             
                  end
         | 
| 23 | 
            -
             | 
| 24 | 
            -
                  sleep  | 
| 25 | 
            -
                   | 
| 26 | 
            -
             | 
| 46 | 
            +
             | 
| 47 | 
            +
                  sleep 8
         | 
| 48 | 
            +
                  wait_for { 
         | 
| 49 | 
            +
                    Process.kill("USR1", pid)
         | 
| 50 | 
            +
                    _, status = Process.wait2(pid)
         | 
| 51 | 
            +
                    expect(status.exitstatus).to be_zero # Must have quit cleanly
         | 
| 52 | 
            +
                  }
         | 
| 27 53 |  | 
| 28 54 | 
             
                  generated_files = Dir.glob('*-result')
         | 
| 29 55 | 
             
                  expect(generated_files).not_to be_empty
         | 
| 30 | 
            -
             | 
| 31 | 
            -
                  stderr.rewind
         | 
| 32 | 
            -
                  log_output = stderr.read
         | 
| 33 | 
            -
                  # This assertion frequently fails (probably because STDERR doesn't get flushed properly)
         | 
| 34 | 
            -
                  # expect(log_output).to include('Stopping (clean shutdown)')
         | 
| 56 | 
            +
                  generated_files.each{|path| File.unlink(path) }
         | 
| 35 57 | 
             
                end
         | 
| 36 58 |  | 
| 37 59 | 
             
                it 'on a TERM signal' do
         | 
| 38 60 | 
             
                  submitter = Sqewer::Connection.default
         | 
| 39 61 |  | 
| 40 | 
            -
                   | 
| 41 | 
            -
             | 
| 42 | 
            -
                
         | 
| 43 | 
            -
                  pid = fork { $stderr.reopen(stderr); $stderr.sync; exec("ruby #{__dir__}/cli_app.rb") }
         | 
| 44 | 
            -
              
         | 
| 62 | 
            +
                  pid = fork { exec("ruby #{__dir__}/cli_app.rb") }
         | 
| 63 | 
            +
             | 
| 45 64 | 
             
                  Thread.new do
         | 
| 46 65 | 
             
                    20.times do
         | 
| 47 | 
            -
                      j = { | 
| 66 | 
            +
                      j = {"_job_class" => 'MyJob', "_job_params" => {first_name: 'John', last_name: 'Doe'}}
         | 
| 48 67 | 
             
                      submitter.send_message(JSON.dump(j))
         | 
| 49 68 | 
             
                    end
         | 
| 50 69 | 
             
                  end
         | 
| 51 | 
            -
             | 
| 52 | 
            -
                  sleep  | 
| 53 | 
            -
                   | 
| 54 | 
            -
             | 
| 70 | 
            +
             | 
| 71 | 
            +
                  sleep 8
         | 
| 72 | 
            +
                  wait_for { 
         | 
| 73 | 
            +
                    Process.kill("TERM", pid)
         | 
| 74 | 
            +
                    _, status = Process.wait2(pid)
         | 
| 75 | 
            +
                    expect(status.exitstatus).to be_zero # Must have quit cleanly
         | 
| 76 | 
            +
                  }
         | 
| 55 77 |  | 
| 56 78 | 
             
                  generated_files = Dir.glob('*-result')
         | 
| 57 79 | 
             
                  expect(generated_files).not_to be_empty
         | 
| 58 80 | 
             
                  generated_files.each{|path| File.unlink(path) }
         | 
| 59 | 
            -
                
         | 
| 60 | 
            -
                  stderr.rewind
         | 
| 61 | 
            -
                  log_output = stderr.read
         | 
| 62 | 
            -
                  # This assertion frequently fails (probably because STDERR doesn't get flushed properly)
         | 
| 63 | 
            -
                  # expect(log_output).to include('Stopping (clean shutdown)')
         | 
| 64 81 | 
             
                end
         | 
| 65 82 | 
             
              end
         | 
| 66 83 | 
             
            end
         | 
| @@ -31,6 +31,17 @@ describe Sqewer::Serializer do | |
| 31 31 | 
             
                  expect(described_class.new.serialize(job)).to eq("{\"_job_class\":\"SomeJob\",\"_job_params\":{\"one\":123,\"two\":[456]}}")
         | 
| 32 32 | 
             
                end
         | 
| 33 33 |  | 
| 34 | 
            +
                it 'adds _execute_after when the value is given' do
         | 
| 35 | 
            +
                  class ThirdJob < Struct.new :one, :two
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
                  
         | 
| 38 | 
            +
                  job = ThirdJob.new(123, [456])
         | 
| 39 | 
            +
                  res = described_class.new.serialize(job, Time.now.to_i + 1500)
         | 
| 40 | 
            +
                  parsed = JSON.load(res)
         | 
| 41 | 
            +
                  
         | 
| 42 | 
            +
                  expect(parsed["_execute_after"]).to be_within(10).of(Time.now.to_i + 1500)
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
                
         | 
| 34 45 | 
             
                it 'raises an exception if the object is of an anonymous class' do
         | 
| 35 46 | 
             
                  s = Struct.new(:foo)
         | 
| 36 47 | 
             
                  o = s.new(1)
         | 
| @@ -58,66 +69,50 @@ describe Sqewer::Serializer do | |
| 58 69 | 
             
              end
         | 
| 59 70 |  | 
| 60 71 | 
             
              describe '#unserialize' do
         | 
| 61 | 
            -
                 | 
| 62 | 
            -
                   | 
| 63 | 
            -
                    class VerySimpleJob; end
         | 
| 64 | 
            -
                    blob  = '{"job_class": "VerySimpleJob"}'
         | 
| 65 | 
            -
                    built_job = described_class.new.unserialize(blob)
         | 
| 66 | 
            -
                    expect(built_job).to be_kind_of(VerySimpleJob)
         | 
| 67 | 
            -
                  end
         | 
| 72 | 
            +
                it 'wraps the job with a Resubmit when the _execute_after key hints that it is too early' do
         | 
| 73 | 
            +
                  class EvenSimplerJob; end
         | 
| 68 74 |  | 
| 69 | 
            -
                   | 
| 70 | 
            -
             | 
| 71 | 
            -
             | 
| 72 | 
            -
             | 
| 73 | 
            -
             | 
| 74 | 
            -
             | 
| 75 | 
            -
                    }.to raise_error(described_class::ArityMismatch)
         | 
| 76 | 
            -
                  end
         | 
| 75 | 
            +
                  timestamp_way_in_the_future = Time.now.to_i + (60 * 60 * 24 * 3)
         | 
| 76 | 
            +
                  blob  = '{"_job_class": "EvenSimplerJob", "_execute_after": %d}' % timestamp_way_in_the_future
         | 
| 77 | 
            +
                  built_job = described_class.new.unserialize(blob)
         | 
| 78 | 
            +
                
         | 
| 79 | 
            +
                  expect(built_job).to be_kind_of(Sqewer::Resubmit)
         | 
| 80 | 
            +
                  expect(built_job.execute_after).to eq(timestamp_way_in_the_future)
         | 
| 77 81 |  | 
| 78 | 
            -
                   | 
| 79 | 
            -
             | 
| 80 | 
            -
                    
         | 
| 81 | 
            -
                    blob  = '{"job_class": "ValidJob", "foo": 1}'
         | 
| 82 | 
            -
                    built_job = described_class.new.unserialize(blob)
         | 
| 83 | 
            -
                    
         | 
| 84 | 
            -
                    expect(built_job).to be_kind_of(ValidJob)
         | 
| 85 | 
            -
                    expect(built_job.foo).to eq(1)
         | 
| 86 | 
            -
                  end
         | 
| 82 | 
            +
                  embedded_job = built_job.job
         | 
| 83 | 
            +
                  expect(embedded_job).to be_kind_of(EvenSimplerJob)
         | 
| 87 84 | 
             
                end
         | 
| 88 85 |  | 
| 89 | 
            -
                 | 
| 90 | 
            -
                   | 
| 91 | 
            -
             | 
| 92 | 
            -
             | 
| 93 | 
            -
             | 
| 94 | 
            -
             | 
| 95 | 
            -
             | 
| 96 | 
            -
             | 
| 97 | 
            -
             | 
| 98 | 
            -
             | 
| 99 | 
            -
             | 
| 100 | 
            -
             | 
| 101 | 
            -
             | 
| 102 | 
            -
             | 
| 103 | 
            -
             | 
| 104 | 
            -
                   | 
| 105 | 
            -
             | 
| 106 | 
            -
             | 
| 107 | 
            -
                     | 
| 108 | 
            -
             | 
| 109 | 
            -
             | 
| 110 | 
            -
             | 
| 111 | 
            -
             | 
| 112 | 
            -
                   | 
| 113 | 
            -
             | 
| 114 | 
            -
             | 
| 115 | 
            -
             | 
| 116 | 
            -
             | 
| 117 | 
            -
             | 
| 118 | 
            -
             | 
| 119 | 
            -
                    expect(built_job.foo).to eq(1)
         | 
| 120 | 
            -
                  end
         | 
| 86 | 
            +
                it 'builds a job without keyword arguments if its constructor does not need any kwargs' do
         | 
| 87 | 
            +
                  class EvenSimplerJob; end
         | 
| 88 | 
            +
                
         | 
| 89 | 
            +
                  blob  = '{"_job_class": "EvenSimplerJob"}'
         | 
| 90 | 
            +
                  built_job = described_class.new.unserialize(blob)
         | 
| 91 | 
            +
                
         | 
| 92 | 
            +
                  expect(built_job).to be_kind_of(EvenSimplerJob)
         | 
| 93 | 
            +
                
         | 
| 94 | 
            +
                  blob  = '{"_job_class": "EvenSimplerJob", "_job_params": null}'
         | 
| 95 | 
            +
                  built_job = described_class.new.unserialize(blob)
         | 
| 96 | 
            +
                
         | 
| 97 | 
            +
                  expect(built_job).to be_kind_of(EvenSimplerJob)
         | 
| 98 | 
            +
                end
         | 
| 99 | 
            +
              
         | 
| 100 | 
            +
                it 'raises an error if the job does not accept the keyword arguments given in the ticket' do
         | 
| 101 | 
            +
                  class MicroJob; end
         | 
| 102 | 
            +
                  blob  = '{"_job_class": "MicroJob", "_job_params":{"foo": 1}}'
         | 
| 103 | 
            +
                  expect {
         | 
| 104 | 
            +
                    described_class.new.unserialize(blob)
         | 
| 105 | 
            +
                  }.to raise_error(ArgumentError)
         | 
| 106 | 
            +
                end
         | 
| 107 | 
            +
              
         | 
| 108 | 
            +
                it 'instantiates the job with keyword arguments' do
         | 
| 109 | 
            +
                  OtherValidJob = Ks.strict(:foo)
         | 
| 110 | 
            +
                
         | 
| 111 | 
            +
                  blob  = '{"_job_class": "OtherValidJob", "_job_params": {"foo": 1}}'
         | 
| 112 | 
            +
                  built_job = described_class.new.unserialize(blob)
         | 
| 113 | 
            +
                
         | 
| 114 | 
            +
                  expect(built_job).to be_kind_of(OtherValidJob)
         | 
| 115 | 
            +
                  expect(built_job.foo).to eq(1)
         | 
| 121 116 | 
             
                end
         | 
| 122 117 | 
             
              end
         | 
| 123 118 | 
             
            end
         | 
| @@ -39,5 +39,23 @@ describe Sqewer::Submitter do | |
| 39 39 | 
             
                  subject = described_class.new(fake_connection, fake_serializer)
         | 
| 40 40 | 
             
                  subject.submit!(:some_object, delay_seconds: 5)
         | 
| 41 41 | 
             
                end
         | 
| 42 | 
            +
                
         | 
| 43 | 
            +
                it 'handles the massively delayed execution by clamping the delay_seconds to the SQS maximum, and saving the _execute_after' do
         | 
| 44 | 
            +
                  fake_serializer = double('Some serializer')
         | 
| 45 | 
            +
                  allow(fake_serializer).to receive(:serialize) {|object_to_serialize, timestamp_seconds|
         | 
| 46 | 
            +
                    
         | 
| 47 | 
            +
                    delay_by = Time.now.to_i + 4585659855
         | 
| 48 | 
            +
                    expect(timestamp_seconds).to be_within(20).of(delay_by)
         | 
| 49 | 
            +
                    
         | 
| 50 | 
            +
                    expect(object_to_serialize).not_to be_nil
         | 
| 51 | 
            +
                    'serialized-object-data'
         | 
| 52 | 
            +
                  }
         | 
| 53 | 
            +
                  
         | 
| 54 | 
            +
                  fake_connection = double('Some SQS connection')
         | 
| 55 | 
            +
                  expect(fake_connection).to receive(:send_message).with('serialized-object-data', {delay_seconds: 899})
         | 
| 56 | 
            +
                  
         | 
| 57 | 
            +
                  subject = described_class.new(fake_connection, fake_serializer)
         | 
| 58 | 
            +
                  subject.submit!(:some_object, delay_seconds: 4585659855)
         | 
| 59 | 
            +
                end
         | 
| 42 60 | 
             
              end
         | 
| 43 61 | 
             
            end
         | 
    
        data/spec/sqewer/worker_spec.rb
    CHANGED
    
    | @@ -22,6 +22,11 @@ describe Sqewer::Worker, :sqs => true do | |
| 22 22 | 
             
                expect(default_worker).to respond_to(:stop)
         | 
| 23 23 | 
             
              end
         | 
| 24 24 |  | 
| 25 | 
            +
              it 'instantiates a new worker object on every call to .default' do
         | 
| 26 | 
            +
                workers = (1..10).map { described_class.default }
         | 
| 27 | 
            +
                expect(workers.uniq.length).to eq(10)
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
              
         | 
| 25 30 | 
             
              it 'instantiates a Logger to STDERR by default' do
         | 
| 26 31 | 
             
                expect(Logger).to receive(:new).with(STDERR)
         | 
| 27 32 | 
             
                worker = described_class.new
         | 
| @@ -57,7 +62,7 @@ describe Sqewer::Worker, :sqs => true do | |
| 57 62 |  | 
| 58 63 | 
             
              context 'when the job cannot be instantiated due to an unknown class' do
         | 
| 59 64 | 
             
                it 'is able to cope with an exception when the job class is unknown (one of generic exceptions)' do
         | 
| 60 | 
            -
                  payload = JSON.dump({ | 
| 65 | 
            +
                  payload = JSON.dump({_job_class: 'UnknownJobClass', _job_params: {arg1: 'some value'}})
         | 
| 61 66 |  | 
| 62 67 | 
             
                  client = Aws::SQS::Client.new
         | 
| 63 68 | 
             
                  client.send_message(queue_url: ENV.fetch('SQS_QUEUE_URL'), message_body: payload)
         | 
| @@ -77,18 +82,18 @@ describe Sqewer::Worker, :sqs => true do | |
| 77 82 | 
             
                it 'sets up the processing pipeline so that jobs can execute in sequence (with threads)' do
         | 
| 78 83 | 
             
                  class SecondaryJob
         | 
| 79 84 | 
             
                    def run
         | 
| 80 | 
            -
                      File.open('secondary-job-run','w') {}
         | 
| 85 | 
            +
                      File.open(File.join(Dir.tmpdir, 'secondary-job-run'),'w') {}
         | 
| 81 86 | 
             
                    end
         | 
| 82 87 | 
             
                  end
         | 
| 83 88 |  | 
| 84 89 | 
             
                  class InitialJob
         | 
| 85 90 | 
             
                    def run(executor)
         | 
| 86 | 
            -
                      File.open('initial-job-run','w') {}
         | 
| 91 | 
            +
                      File.open(File.join(Dir.tmpdir, 'initial-job-run'),'w') {}
         | 
| 87 92 | 
             
                      executor.submit!(SecondaryJob.new)
         | 
| 88 93 | 
             
                    end
         | 
| 89 94 | 
             
                  end
         | 
| 90 95 |  | 
| 91 | 
            -
                  payload = JSON.dump({ | 
| 96 | 
            +
                  payload = JSON.dump({_job_class: 'InitialJob'})
         | 
| 92 97 | 
             
                  client = Aws::SQS::Client.new
         | 
| 93 98 | 
             
                  client.send_message(queue_url: ENV.fetch('SQS_QUEUE_URL'), message_body: payload)
         | 
| 94 99 |  | 
| @@ -97,11 +102,8 @@ describe Sqewer::Worker, :sqs => true do | |
| 97 102 | 
             
                  worker.start
         | 
| 98 103 |  | 
| 99 104 | 
             
                  begin
         | 
| 100 | 
            -
                    wait_for { File.exist?('initial-job-run') }.to eq(true)
         | 
| 101 | 
            -
                    wait_for { File.exist?('secondary-job-run') }.to eq(true)
         | 
| 102 | 
            -
                    
         | 
| 103 | 
            -
                    File.unlink('initial-job-run')
         | 
| 104 | 
            -
                    File.unlink('secondary-job-run')
         | 
| 105 | 
            +
                    wait_for { File.exist?(File.join(Dir.tmpdir, 'initial-job-run')) }.to eq(true)
         | 
| 106 | 
            +
                    wait_for { File.exist?(File.join(Dir.tmpdir, 'secondary-job-run')) }.to eq(true)
         | 
| 105 107 | 
             
                  ensure
         | 
| 106 108 | 
             
                    worker.stop
         | 
| 107 109 | 
             
                  end
         |