disqualified 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9912dd95e6d0ffe2a78c0ac5e2d12683d16898d2ac329f7c50f1add7779ad3ea
4
- data.tar.gz: 98ee2d4e7581fe04cbceed91904cb280b9a0042e6cb38ebe738103b441edecb8
3
+ metadata.gz: fbe745886eb9d17ecb6537e23724c48423523695e7c3c1243e166116710d99c0
4
+ data.tar.gz: f4f9f74ec95f4d3f1f3a8cd2a95907b7d247708676b9c7134c88026813bb7363
5
5
  SHA512:
6
- metadata.gz: 3e27a52fd2e01580afcfdac1a66511ddb2fa70faf4f67caccefde8343fabffa4f7e527ec7257e2c9b2f5d7d9e8680b5f614846332c084c2311fd7c3f8548b806
7
- data.tar.gz: 3242e97e5e18fa7ff0ea60199ba8abbeb504277e26dfab3cbf2896e63eee53b7fda96c152ea76ed49c01c317492c361f4699c94478c1aa428260eb526ce2c2ef
6
+ metadata.gz: 1b2d18b8f154938fcb9a6231aa9ba4edd544b06d9a78dba0f7e1def10b12c597d2258f60a5fd7e7ad9704700dab1f3584c96d94a732a26cceba8f4989166d5a7
7
+ data.tar.gz: 5c648be8f80189afadc35f90a9e6f3c713550626dfc8744629a3867e8b989552c8455f449fef530c9aa13bbeea4be4acbc9654f36a765b48767051af0e731cbb
@@ -1,7 +1,18 @@
1
1
  class Disqualified::Record < Disqualified::BaseRecord
2
2
  self.table_name = "disqualified_jobs"
3
3
 
4
- scope :runnable, -> { where(finished_at: nil, run_at: (..Time.now), locked_by: nil) }
4
+ belongs_to :disqualified_sequence,
5
+ class_name: "Disqualified::SequenceRecord",
6
+ foreign_key: "sequence_uuid",
7
+ primary_key: "uuid",
8
+ optional: true
9
+
10
+ scope :with_sequence, -> {
11
+ joins("LEFT OUTER JOIN disqualified_sequences ds ON ds.uuid = sequence_uuid AND ds.current_step = sequence_step")
12
+ .where("ds.uuid = sequence_uuid OR (ds.uuid IS NULL AND sequence_uuid IS NULL)")
13
+ }
14
+ scope :pending, -> { where(finished_at: nil, run_at: (..Time.now), locked_by: nil) }
15
+ scope :runnable, -> { with_sequence.pending }
5
16
 
6
17
  def self.claim_one!(id: nil)
7
18
  run_id = SecureRandom.uuid
@@ -22,31 +33,52 @@ class Disqualified::Record < Disqualified::BaseRecord
22
33
  attempts: Arel.sql("attempts + 1")
23
34
  )
24
35
 
25
- raise ActiveRecord::RecordNotFound if claimed_count == 0
36
+ raise Disqualified::Error::NoClaimableJob if claimed_count == 0
26
37
 
27
38
  Disqualified::Record.find_by!(locked_by: run_id)
39
+ rescue ActiveRecord::RecordNotFound
40
+ raise Disqualified::Error::NoClaimableJob
28
41
  end
29
42
 
30
43
  def run!
31
44
  record = self.class.claim_one!(id:)
32
- record.send(:instantiate_handler_and_perform_with_args)
33
- record.finish
45
+ begin
46
+ record.send(:instantiate_handler_and_perform_with_args)
47
+ rescue => e
48
+ record.unclaim
49
+ raise e
50
+ else
51
+ record.finish
52
+ end
34
53
  record
35
54
  end
36
55
 
37
56
  def finish
38
- update!(locked_by: nil, locked_at: nil, finished_at: Time.now)
57
+ transaction do
58
+ update!(locked_by: nil, locked_at: nil, finished_at: Time.now)
59
+ if sequence_uuid && sequence_step
60
+ Disqualified::SequenceRecord
61
+ .where(uuid: sequence_uuid, current_step: sequence_step)
62
+ .update_all(
63
+ current_step: sequence_step + 1,
64
+ updated_at: Time.now
65
+ )
66
+ end
67
+ end
39
68
  end
40
69
 
41
70
  def requeue
42
71
  retry_count = attempts - 1
43
72
  sleep = (retry_count**4) + 15 + (rand(10) * (retry_count + 1))
44
- unqueue(run_at: Time.now + sleep)
73
+ unclaim(next_run_at: Time.now + sleep)
45
74
  end
46
75
 
47
- def unqueue(run_at: nil)
48
- run_at ||= Time.now
49
- update!(locked_by: nil, locked_at: nil, run_at:)
76
+ def unclaim(next_run_at: nil)
77
+ if next_run_at
78
+ update!(locked_by: nil, locked_at: nil, run_at: next_run_at)
79
+ else
80
+ update!(locked_by: nil, locked_at: nil)
81
+ end
50
82
  end
51
83
 
52
84
  private def instantiate_handler_and_perform_with_args
@@ -0,0 +1,3 @@
1
+ class Disqualified::SequenceRecord < Disqualified::BaseRecord
2
+ self.table_name = "disqualified_sequences"
3
+ end
@@ -8,5 +8,8 @@ module Disqualified
8
8
 
9
9
  class JobNotClaimed < DisqualifiedError
10
10
  end
11
+
12
+ class NoClaimableJob < DisqualifiedError
13
+ end
11
14
  end
12
15
  end
@@ -1,11 +1,19 @@
1
1
  module Disqualified::Job
2
2
  module ClassMethods
3
3
  def perform_at(the_time, *args)
4
+ if Thread.current[Disqualified::Sequence::UUID]
5
+ Thread.current[Disqualified::Sequence::COUNT] += 1
6
+ sequence_uuid = Thread.current[Disqualified::Sequence::UUID]
7
+ sequence_step = Thread.current[Disqualified::Sequence::COUNT]
8
+ end
9
+
4
10
  Disqualified::Record.create!(
5
11
  handler: name,
6
12
  arguments: JSON.dump(args),
7
13
  queue: "default",
8
- run_at: the_time
14
+ run_at: the_time,
15
+ sequence_uuid:,
16
+ sequence_step:
9
17
  )
10
18
  end
11
19
 
@@ -18,7 +26,7 @@ module Disqualified::Job
18
26
  end
19
27
  end
20
28
 
21
- def self.included(klass)
22
- klass.extend(ClassMethods)
29
+ def self.included(other)
30
+ other.extend(ClassMethods)
23
31
  end
24
32
  end
@@ -8,28 +8,21 @@ class Disqualified::Main
8
8
 
9
9
  def call
10
10
  Rails.application.reloader.wrap do
11
- begin
12
- record = Disqualified::Record.claim_one!
13
- run_id = record.locked_by
14
- rescue ActiveRecord::RecordNotFound
15
- @logger.warn do
16
- format_log("Disqualified::Main#call", "Job not found")
17
- end
18
- next
11
+ record = Disqualified::Record.claim_one!
12
+ run_id = record.locked_by
13
+ record.send(:instantiate_handler_and_perform_with_args)
14
+ record.finish
15
+ @logger.info do
16
+ format_log("Disqualified::Main#call", "Runner #{run_id}", "Done")
19
17
  end
20
-
21
- begin
22
- record.send(:instantiate_handler_and_perform_with_args)
23
- record.finish
24
-
25
- @logger.info do
26
- format_log("Disqualified::Main#call", "Runner #{run_id}", "Done")
27
- end
28
- rescue => e
29
- handle_error(@error_hooks, e, {record: record.attributes})
30
- @logger.error { format_log("Disqualified::Main#run", "Runner #{run_id}", "Rescued Record ##{record.id}") }
31
- record.requeue
18
+ rescue Disqualified::Error::NoClaimableJob
19
+ @logger.warn do
20
+ format_log("Disqualified::Main#call", "No claimable jobs")
32
21
  end
22
+ rescue => e
23
+ handle_error(@error_hooks, e, {record: record.attributes})
24
+ @logger.error { format_log("Disqualified::Main#run", "Runner #{run_id}", "Rescued Record ##{record.id}") }
25
+ record.requeue
33
26
  end
34
27
  end
35
28
  end
@@ -0,0 +1,21 @@
1
+ class Disqualified::Sequence
2
+ UUID = :disqualified_sequence_uuid
3
+ COUNT = :disqualified_sequence_count
4
+
5
+ def self.queue(description: nil, &block)
6
+ Disqualified::SequenceRecord.transaction do
7
+ Thread.current[UUID] = SecureRandom.uuid
8
+ Thread.current[COUNT] = 0
9
+ yield
10
+ Disqualified::SequenceRecord.create!(
11
+ uuid: Thread.current[UUID],
12
+ current_step: 1,
13
+ final_step: Thread.current[COUNT],
14
+ description:
15
+ )
16
+ end
17
+ ensure
18
+ Thread.current[UUID] = nil
19
+ Thread.current[COUNT] = nil
20
+ end
21
+ end
@@ -1,3 +1,3 @@
1
1
  module Disqualified
2
- VERSION = "0.4.0"
2
+ VERSION = "0.5.0"
3
3
  end
data/lib/disqualified.rb CHANGED
@@ -17,4 +17,5 @@ require_relative "disqualified/engine"
17
17
  require_relative "disqualified/job"
18
18
  require_relative "disqualified/main"
19
19
  require_relative "disqualified/pool"
20
+ require_relative "disqualified/sequence"
20
21
  require_relative "disqualified/version"
@@ -3,6 +3,8 @@ Description:
3
3
 
4
4
  Example:
5
5
  bin/rails generate disqualified:install
6
+ bin/rails generate disqualified:install --database primary
7
+ bin/rails g disqualified:install --db=animals
6
8
 
7
9
  This will create:
8
10
  db/migrate/20220703062536_create_disqualified_jobs.rb
@@ -1,8 +1,20 @@
1
+ require "rails/generators/active_record"
2
+
1
3
  class Disqualified::InstallGenerator < Rails::Generators::Base
4
+ include ActiveRecord::Generators::Migration
5
+
2
6
  source_root File.expand_path("templates", __dir__)
3
7
 
8
+ class_option :database,
9
+ type: :string,
10
+ aliases: %i[--db],
11
+ desc: "The database for your migration. By default, the current environment's primary database is used."
12
+
4
13
  def copy_migration_file
5
14
  basename = "20220703062536_create_disqualified_jobs.rb"
6
- copy_file basename, "db/migrate/#{basename}"
15
+ copy_file(basename, File.join(db_migrate_path, basename))
16
+
17
+ basename = "20241119023328_create_disqualified_sequences.rb"
18
+ copy_file(basename, File.join(db_migrate_path, basename))
7
19
  end
8
20
  end
@@ -0,0 +1,17 @@
1
+ class CreateDisqualifiedSequences < ActiveRecord::Migration[7.2]
2
+ def change
3
+ create_table :disqualified_sequences do |t|
4
+ t.text :uuid, null: false
5
+ t.integer :current_step, null: false
6
+ t.integer :final_step, null: false
7
+ t.text :description
8
+ t.timestamps
9
+
10
+ t.index :uuid, unique: true
11
+ end
12
+
13
+ add_column :disqualified_jobs, :sequence_uuid, :text
14
+ add_column :disqualified_jobs, :sequence_step, :integer
15
+ add_index :disqualified_jobs, [:sequence_uuid, :sequence_step], unique: true
16
+ end
17
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: disqualified
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zach Ahn
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-08-11 00:00:00.000000000 Z
11
+ date: 2024-12-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -50,6 +50,7 @@ files:
50
50
  - README.md
51
51
  - app/models/disqualified/base_record.rb
52
52
  - app/models/disqualified/record.rb
53
+ - app/models/disqualified/sequence_record.rb
53
54
  - disqualified.gemspec
54
55
  - exe/disqualified
55
56
  - lib/disqualified.rb
@@ -63,10 +64,12 @@ files:
63
64
  - lib/disqualified/logging.rb
64
65
  - lib/disqualified/main.rb
65
66
  - lib/disqualified/pool.rb
67
+ - lib/disqualified/sequence.rb
66
68
  - lib/disqualified/version.rb
67
69
  - lib/generators/disqualified/install/USAGE
68
70
  - lib/generators/disqualified/install/install_generator.rb
69
71
  - lib/generators/disqualified/install/templates/20220703062536_create_disqualified_jobs.rb
72
+ - lib/generators/disqualified/install/templates/20241119023328_create_disqualified_sequences.rb
70
73
  homepage: https://github.com/zachahn/disqualified
71
74
  licenses:
72
75
  - LGPL-3.0-only