crono_trigger 0.7.0 → 0.8.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9d0ca54718a635b6c32268bcb6ed480683d038923eb5f62cda38e91e3d43356a
4
- data.tar.gz: aa5d62ef5ecf4003391485e7392bc6493035a50ce73ca852fc4fa26619b17b2d
3
+ metadata.gz: 734da2ad0480e79b440d8ef73f9b83fb88f13e6f6510513340c62b70c3750c39
4
+ data.tar.gz: b338b9c86a9fdf01d0ba739fa9f53c9536393cec05d7fe5c8943fe05782ad7b4
5
5
  SHA512:
6
- metadata.gz: 54ed50aac9d11ae950e1cad9651a8a4c27a5a07f169eb2c92c8f2c761420f9e6ed2a5b83965df91e7e14e67128ee6a0698f5a6a9d5d6566946b8544f8795dcb0
7
- data.tar.gz: 10422746cbf88079591790766fd4e58f9152787e7a9ead6a0f94dbbd286cfc4caab8f69c6547716143db6584c7d6ab5e571435013d17f2ed1e833f77502d745d
6
+ metadata.gz: 6e73b97cece87a4b887e4cec1c5cbd153cc9ad51c3de1956c38ef2a5000fa74c0d3e52c07401c0aa033f0921852a2f6be85533aea050d425dc220c591681a210
7
+ data.tar.gz: dfbec13afaa581a544b50481fa54509ace24de39f8ecb6d99788e508bd680da1e5afd89abeb0cde7be8ad8db3c7c4b56ae67dbdf0bd087775eaeed62b92d8cac
@@ -12,6 +12,9 @@ jobs:
12
12
  strategy:
13
13
  matrix:
14
14
  ruby-version: ['2.7', '3.0', '3.1']
15
+ gemfile: ["Gemfile", "gemfiles/activerecord-61.gemfile", "gemfiles/activerecord-70.gemfile", "gemfiles/activerecord-71.gemfile"]
16
+ env:
17
+ BUNDLE_GEMFILE: ${{ matrix.gemfile }}
15
18
 
16
19
  steps:
17
20
  - uses: actions/checkout@v2
data/.gitignore CHANGED
@@ -18,3 +18,6 @@ spec/dummy/db/*.sqlite3
18
18
  spec/dummy/db/*.sqlite3-journal
19
19
  spec/dummy/log/*.log
20
20
  spec/dummy/tmp/
21
+ spec/testdb.sqlite3*
22
+
23
+ .gem_rbs_collection
@@ -1,5 +1,5 @@
1
1
  source "https://rubygems.org"
2
2
 
3
- gem "activerecord", "~> 5.0.0"
3
+ gem "activerecord", "~> 6.1.0"
4
4
 
5
5
  gemspec :path => "../"
@@ -1,5 +1,5 @@
1
1
  source "https://rubygems.org"
2
2
 
3
- gem "activerecord", "~> 5.1.0"
3
+ gem "activerecord", "~> 7.0.0"
4
4
 
5
5
  gemspec :path => "../"
@@ -1,5 +1,5 @@
1
1
  source "https://rubygems.org"
2
2
 
3
- gem "activerecord", "~> 5.2.0"
3
+ gem "activerecord", "~> 7.1.0"
4
4
 
5
5
  gemspec :path => "../"
@@ -8,7 +8,12 @@ module CronoTrigger
8
8
  ALIVE_THRESHOLD = CronoTrigger::Worker::HEARTBEAT_INTERVAL * 5
9
9
 
10
10
  enum executor_status: {running: "running", quiet: "quiet", shuttingdown: "shuttingdown", shutdown: "shutdown"}
11
- serialize :polling_model_names, JSON
11
+
12
+ if ActiveRecord.version >= Gem::Version.new("7.1.0")
13
+ serialize :polling_model_names, coder: JSON
14
+ else
15
+ serialize :polling_model_names, JSON
16
+ end
12
17
 
13
18
  scope :alive_workers, proc { where(arel_table[:last_heartbeated_at].gteq(Time.current - ALIVE_THRESHOLD)) }
14
19
  end
@@ -10,6 +10,7 @@ module CronoTrigger
10
10
  end
11
11
  @execution_counter = execution_counter
12
12
  @quiet = Concurrent::AtomicBoolean.new(false)
13
+ @worker_count = 1
13
14
  end
14
15
 
15
16
  def run
@@ -58,7 +59,7 @@ module CronoTrigger
58
59
  maybe_has_next = true
59
60
  while maybe_has_next && !@stop_flag.set?
60
61
  records, maybe_has_next = model.connection_pool.with_connection do
61
- model.executables_with_lock(limit: CronoTrigger.config.fetch_records || CronoTrigger.config.executor_thread * 3)
62
+ model.executables_with_lock(limit: CronoTrigger.config.fetch_records || CronoTrigger.config.executor_thread * 3, worker_count: @worker_count)
62
63
  end
63
64
 
64
65
  records.each do |record|
@@ -74,6 +75,11 @@ module CronoTrigger
74
75
  end
75
76
  end
76
77
 
78
+ def worker_count=(n)
79
+ raise ArgumentError, "worker_count must be greater than 0" if n <= 0
80
+ @worker_count = n
81
+ end
82
+
77
83
  private
78
84
 
79
85
  def process_record(record)
@@ -63,8 +63,11 @@ module CronoTrigger
63
63
  end
64
64
 
65
65
  module ClassMethods
66
- def executables_with_lock(limit: CronoTrigger.config.executor_thread * 3)
67
- ids = executables(limit: limit).pluck(:id)
66
+ def executables_with_lock(limit: CronoTrigger.config.executor_thread * 3, worker_count: 1)
67
+ # Fetch more than `limit` records because other workers might have acquired the lock
68
+ # and this method might not be able to return enough records for the executor to
69
+ # make the best use of the CPU.
70
+ ids = executables(limit: limit * worker_count).pluck(:id)
68
71
  maybe_has_next = !ids.empty?
69
72
  records = []
70
73
  ids.each do |id|
@@ -75,6 +78,8 @@ module CronoTrigger
75
78
  records << r
76
79
  end
77
80
  end
81
+
82
+ return [records, maybe_has_next] if records.size == limit
78
83
  end
79
84
  [records, maybe_has_next]
80
85
  end
@@ -1,3 +1,3 @@
1
1
  module CronoTrigger
2
- VERSION = "0.7.0"
2
+ VERSION = "0.8.0"
3
3
  end
@@ -7,6 +7,7 @@ module CronoTrigger
7
7
  HEARTBEAT_INTERVAL = 60
8
8
  SIGNAL_FETCH_INTERVAL = 10
9
9
  MONITOR_INTERVAL = 20
10
+ WORKER_COUNT_UPDATE_INTERVAL = 60
10
11
  EXECUTOR_SHUTDOWN_TIMELIMIT = 300
11
12
  OTHER_THREAD_SHUTDOWN_TIMELIMIT = 120
12
13
  attr_reader :polling_threads
@@ -37,6 +38,7 @@ module CronoTrigger
37
38
  @heartbeat_thread = run_heartbeat_thread
38
39
  @signal_fetcn_thread = run_signal_fetch_thread
39
40
  @monitor_thread = run_monitor_thread
41
+ @worker_count_updater_thread = run_worker_count_updater_thread
40
42
 
41
43
  polling_thread_count = CronoTrigger.config.polling_thread || [@model_names.size, Concurrent.processor_count].min
42
44
  # Assign local variable for Signal handling
@@ -58,6 +60,7 @@ module CronoTrigger
58
60
  @executor.wait_for_termination(EXECUTOR_SHUTDOWN_TIMELIMIT)
59
61
  @heartbeat_thread.join(OTHER_THREAD_SHUTDOWN_TIMELIMIT)
60
62
  @signal_fetcn_thread.join(OTHER_THREAD_SHUTDOWN_TIMELIMIT)
63
+ @worker_count_updater_thread.join(OTHER_THREAD_SHUTDOWN_TIMELIMIT)
61
64
 
62
65
  unregister
63
66
  end
@@ -104,6 +107,15 @@ module CronoTrigger
104
107
  end
105
108
  end
106
109
 
110
+ def run_worker_count_updater_thread
111
+ update_worker_count
112
+ Thread.start do
113
+ until @stop_flag.wait_for_set(WORKER_COUNT_UPDATE_INTERVAL)
114
+ update_worker_count
115
+ end
116
+ end
117
+ end
118
+
107
119
  def heartbeat
108
120
  CronoTrigger::Models::Worker.connection_pool.with_connection do
109
121
  begin
@@ -162,7 +174,7 @@ module CronoTrigger
162
174
  return unless ActiveSupport::Notifications.notifier.listening?(CronoTrigger::Events::MONITOR)
163
175
 
164
176
  CronoTrigger::Models::Worker.connection_pool.with_connection do
165
- if CronoTrigger.workers.where("polling_model_names = ?", @model_names.to_json).order(:worker_id).limit(1).pluck(:worker_id).first != @crono_trigger_worker_id
177
+ if workers_processing_same_models.order(:worker_id).limit(1).pluck(:worker_id).first != @crono_trigger_worker_id
166
178
  # Return immediately to avoid redundant instruments
167
179
  return
168
180
  end
@@ -189,5 +201,19 @@ module CronoTrigger
189
201
  rescue => ex
190
202
  CronoTrigger::GlobalExceptionHandler.handle_global_exception(ex)
191
203
  end
204
+
205
+ def update_worker_count
206
+ CronoTrigger::Models::Worker.connection_pool.with_connection do
207
+ worker_count = workers_processing_same_models.count
208
+ return if worker_count.zero?
209
+ @polling_threads.each { |th| th.worker_count = worker_count }
210
+ end
211
+ rescue => ex
212
+ CronoTrigger::GlobalExceptionHandler.handle_global_exception(ex)
213
+ end
214
+
215
+ def workers_processing_same_models
216
+ CronoTrigger.workers.where("polling_model_names = ?", @model_names.to_json)
217
+ end
192
218
  end
193
219
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: crono_trigger
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - joker1007
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-06-07 00:00:00.000000000 Z
11
+ date: 2024-03-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: chrono
@@ -247,7 +247,6 @@ files:
247
247
  - ".github/workflows/rspec.yml"
248
248
  - ".gitignore"
249
249
  - ".rspec"
250
- - ".travis.yml"
251
250
  - Gemfile
252
251
  - LICENSE.txt
253
252
  - README.md
@@ -257,9 +256,9 @@ files:
257
256
  - crono_trigger.gemspec
258
257
  - exe/crono_trigger
259
258
  - exe/crono_trigger-web
260
- - gemfiles/activerecord-50.gemfile
261
- - gemfiles/activerecord-51.gemfile
262
- - gemfiles/activerecord-52.gemfile
259
+ - gemfiles/activerecord-61.gemfile
260
+ - gemfiles/activerecord-70.gemfile
261
+ - gemfiles/activerecord-71.gemfile
263
262
  - lib/crono_trigger.rb
264
263
  - lib/crono_trigger/cli.rb
265
264
  - lib/crono_trigger/events.rb
@@ -341,7 +340,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
341
340
  - !ruby/object:Gem::Version
342
341
  version: '0'
343
342
  requirements: []
344
- rubygems_version: 3.4.10
343
+ rubygems_version: 3.5.3
345
344
  signing_key:
346
345
  specification_version: 4
347
346
  summary: In Service Asynchronous Job Scheduler for Rails
data/.travis.yml DELETED
@@ -1,18 +0,0 @@
1
- sudo: false
2
- language: ruby
3
- cache: bundler
4
- rvm:
5
- - 2.7.0
6
- - 2.6.3
7
- gemfile:
8
- - gemfiles/activerecord-52.gemfile
9
- before_install:
10
- - gem i bundler
11
- - mysql -e 'CREATE DATABASE IF NOT EXISTS test;'
12
- services:
13
- - mysql
14
- env:
15
- - DB=sqlite
16
- - DB=mysql MYSQL_RESTART_COMMAND="sudo service mysql restart"
17
- - NO_TIMESTAMP=false
18
- - NO_TIMESTAMP=true