periodically 0.0.1 → 0.0.2

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: 39405716f55a3c85a4674d38d0440ba293d9bea7e44a260e062b2e631dc230b8
4
- data.tar.gz: f51dbc7e4d9a033778107700e6c82c8743374e9705e8526f84e7900ac56e6cdc
3
+ metadata.gz: 8606b68187a8ed711211079f83437e183a35b16c896d5e54f8c091717bd099cf
4
+ data.tar.gz: f30a109baee2a14159db2d8efb08b59a795c4ced31085e12fbc3a36878ef80cc
5
5
  SHA512:
6
- metadata.gz: f65b70c130c7dffd6cb01da0c02992a4ff4bec0bf763a46ed996057a047709871aabd07f0efb5fa79708a40e5c2d4c33da263c4fdcb0726644af8ad3494517c0
7
- data.tar.gz: fe4a38609d1b958f748cbeaae53f571ce0d005318599d49d96a6ae0d788db1bde0c96a05b32fb9908c33864b7529aa4930d09d2806d843b1948cd6cad81026ee
6
+ metadata.gz: 4a4062005b2f44f31febb25be53f77d1afd765555dba06656456cf882e782c2e889fb8fe2cf6a2346ace47a033be85a2ce798a2cf23e10a437ca877b0f83b46d
7
+ data.tar.gz: 6020c84dcd0e0829e1d1b3e1c2dcd5fe6cbee482ef66f9be43fb8102bdadb212c9c0301e4f4b02b21fd454a3d235467f8f548bc7f70dbc7fc557bcb917c9d98e
data/.editorconfig CHANGED
@@ -4,6 +4,6 @@ root = true
4
4
  end_of_line = lf
5
5
  insert_final_newline = true
6
6
 
7
- [*.rb,*.gemspec]
7
+ [*.{rb,gemspec}}]
8
8
  indent_style = space
9
9
  indent_size = 2
data/Gemfile CHANGED
@@ -1,5 +1,14 @@
1
- source 'https://rubygems.org'
2
-
3
- gem 'activerecord'
4
- gem 'redis-namespace'
5
- gem 'rufus-scheduler'
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rake'
4
+ gem 'activerecord'
5
+ gem 'redis-namespace'
6
+ gem 'rufus-scheduler'
7
+
8
+ group :test do
9
+ gem 'minitest'
10
+ end
11
+
12
+ group :development, :test do
13
+ gem 'standard'
14
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,68 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ activemodel (6.0.2.1)
5
+ activesupport (= 6.0.2.1)
6
+ activerecord (6.0.2.1)
7
+ activemodel (= 6.0.2.1)
8
+ activesupport (= 6.0.2.1)
9
+ activesupport (6.0.2.1)
10
+ concurrent-ruby (~> 1.0, >= 1.0.2)
11
+ i18n (>= 0.7, < 2)
12
+ minitest (~> 5.1)
13
+ tzinfo (~> 1.1)
14
+ zeitwerk (~> 2.2)
15
+ ast (2.4.0)
16
+ concurrent-ruby (1.1.5)
17
+ et-orbi (1.2.2)
18
+ tzinfo
19
+ fugit (1.3.3)
20
+ et-orbi (~> 1.1, >= 1.1.8)
21
+ raabro (~> 1.1)
22
+ i18n (1.7.0)
23
+ concurrent-ruby (~> 1.0)
24
+ jaro_winkler (1.5.4)
25
+ minitest (5.13.0)
26
+ parallel (1.19.1)
27
+ parser (2.7.0.1)
28
+ ast (~> 2.4.0)
29
+ raabro (1.1.6)
30
+ rainbow (3.0.0)
31
+ rake (13.0.1)
32
+ redis (4.1.3)
33
+ redis-namespace (1.7.0)
34
+ redis (>= 3.0.4)
35
+ rubocop (0.77.0)
36
+ jaro_winkler (~> 1.5.1)
37
+ parallel (~> 1.10)
38
+ parser (>= 2.6)
39
+ rainbow (>= 2.2.2, < 4.0)
40
+ ruby-progressbar (~> 1.7)
41
+ unicode-display_width (>= 1.4.0, < 1.7)
42
+ rubocop-performance (1.5.2)
43
+ rubocop (>= 0.71.0)
44
+ ruby-progressbar (1.10.1)
45
+ rufus-scheduler (3.6.0)
46
+ fugit (~> 1.1, >= 1.1.6)
47
+ standard (0.1.7)
48
+ rubocop (~> 0.77.0)
49
+ rubocop-performance (~> 1.5.1)
50
+ thread_safe (0.3.6)
51
+ tzinfo (1.2.6)
52
+ thread_safe (~> 0.1)
53
+ unicode-display_width (1.6.0)
54
+ zeitwerk (2.2.2)
55
+
56
+ PLATFORMS
57
+ ruby
58
+
59
+ DEPENDENCIES
60
+ activerecord
61
+ minitest
62
+ rake
63
+ redis-namespace
64
+ rufus-scheduler
65
+ standard
66
+
67
+ BUNDLED WITH
68
+ 2.1.2
data/README.md CHANGED
@@ -11,18 +11,25 @@ Example usecases:
11
11
  - Launch a non-important sync operation depending on a specific condition (e.g. NULL value in some database column)
12
12
  - Achievable by checking the column against NULL inside the `on` condition
13
13
 
14
- ### Example usage with Rails
14
+ ## Getting started with Rails
15
15
 
16
- ```rb
17
- # config/initializers/periodically.rb
18
- require "periodically"
16
+ **Add gem to Gemfile and install**
17
+
18
+ `gem 'periodically'` && `bundle install`
19
19
 
20
- # Note: in development mode classes are loaded lazily, so periodical jobs only start once classes have been loaded
21
- # In production classes are loaded eagerly, so this is no problem
20
+ **Add an initializer (e.g. `config/initializers/periodically.rb`)**
22
21
 
22
+ ```rb
23
+ require "periodically"
23
24
  Periodically.start
24
25
  ```
25
26
 
27
+ In Rails, Periodically jobs are only registered when the class is loaded.
28
+ In production mode Rails (by default) eagerly loads all classes, meaning that everything is fine.
29
+ However, in development mode you might want to either disable eager mode with `config.eager_load = false`
30
+
31
+ **Utilize Periodically in e.g. a Model**
32
+
26
33
  ```rb
27
34
  # app/models/item.rb
28
35
 
@@ -41,12 +48,6 @@ class Item < ApplicationRecord
41
48
  end
42
49
  ```
43
50
 
44
- ### Example usage with pure Ruby
45
-
46
- ```rb
47
- # TODO
48
- ```
49
-
50
51
  ## Execution model
51
52
 
52
53
  Periodically launches a single background thread, which executes registered queries every x seconds. If a pending query is found, the registered callback method is called in the same thread. Hence, a blocking callback method will also block execution of other pending queries.
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+ require "standard/rake"
4
+
5
+ Rake::TestTask.new(:test) do |test|
6
+ test.warning = true
7
+ test.pattern = "test/**/test_*.rb"
8
+ end
9
+
10
+ task default: [:standard, :test]
data/lib/periodically.rb CHANGED
@@ -1,8 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "periodically/job"
4
+ require "periodically/debug"
4
5
  require "periodically/redis"
5
- require "periodically/model" if defined?(::Rails::Engine)
6
+ require "periodically/model"
6
7
 
7
8
  module Periodically
8
9
  @@registered = []
@@ -27,6 +28,10 @@ module Periodically
27
28
  def self.register(klass, method, opts)
28
29
  @@registered.push(Periodically::Job.new(klass, method, opts))
29
30
  end
31
+
32
+ def self._registered_jobs
33
+ @@registered
34
+ end
30
35
 
31
36
  def self.redis_pool
32
37
  @redis ||= Periodically::RedisConnection.create(REDIS_DEFAULTS)
@@ -40,13 +45,18 @@ module Periodically
40
45
  end
41
46
 
42
47
  def self.start
43
- require 'rufus-scheduler'
48
+ require "rufus-scheduler"
44
49
  scheduler = Rufus::Scheduler.new
45
50
 
46
51
  Periodically.redis { |conn| conn.ping }
47
52
 
48
- scheduler.interval '10s' do
53
+ scheduler.interval "10s" do
49
54
  Periodically.execute_next
50
55
  end
51
56
  end
52
57
  end
58
+
59
+ if defined?(::Rails::Engine) && !Rails.application.config.eager_load
60
+ message = "Periodically initialized without Rails eager loading; some jobs may not be launched until the classes have been loaded"
61
+ Periodically.logger.warn(message)
62
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Periodically
4
+ module Debug
5
+ def self.total_debug_dump
6
+ error_counts = Periodically.redis do |conn|
7
+ conn.scan_each(:match => "errors:*").to_a
8
+ end
9
+ locks = Periodically.redis do |conn|
10
+ conn.scan_each(:match => "locks:*").to_a
11
+ end
12
+ { job_count: Periodically._registered_jobs.size, error_counts: error_counts, locks: locks }
13
+ end
14
+ end
15
+ end
16
+
@@ -7,6 +7,7 @@ module Periodically
7
7
  def initialize(klass, method, opts)
8
8
  @klass = klass
9
9
  @method = method
10
+ @job_key = "#{klass.name}/#{method.to_s}"
10
11
  @opts = opts
11
12
  end
12
13
 
@@ -36,26 +37,26 @@ module Periodically
36
37
 
37
38
  private
38
39
 
39
- def instance_key(instance)
40
- instance.cache_key_with_version
41
- end
42
-
43
- def instance_locked?(instance)
44
- Periodically.redis {|conn| conn.exists("locks:#{instance_key(instance)}")}
40
+ def full_instance_key(instance)
41
+ "#{@job_key}/#{instance.id}"
45
42
  end
46
43
 
47
44
  def increase_instance_error_count(instance)
48
- error_count_key = "errors:#{instance_key(instance)}"
45
+ error_count_key = "errors:#{full_instance_key(instance)}"
49
46
  Periodically.redis {|conn| conn.incr(error_count_key)}
50
47
  end
51
48
 
52
49
  def clear_instance_error_count(instance)
53
- error_count_key = "errors:#{instance_key(instance)}"
50
+ error_count_key = "errors:#{full_instance_key(instance)}"
54
51
  Periodically.redis {|conn| conn.del(error_count_key)}
55
52
  end
56
53
 
54
+ def instance_locked?(instance)
55
+ Periodically.redis {|conn| conn.exists("locks:#{full_instance_key(instance)}")}
56
+ end
57
+
57
58
  def lock_instance(instance, seconds)
58
- lock_key = "locks:#{instance_key(instance)}"
59
+ lock_key = "locks:#{full_instance_key(instance)}"
59
60
 
60
61
  Periodically.redis do |conn|
61
62
  conn.multi do |multi|
@@ -1,17 +1,15 @@
1
- # frozen_string_literal: true
2
-
3
- module Periodically
4
- module Model
5
- extend ActiveSupport::Concern
6
-
7
- def self.included(base)
8
- base.extend ClassMethods
9
- end
10
-
11
- module ClassMethods
12
- def periodically(symbol, **opts)
13
- Periodically.register(self, symbol, opts)
14
- end
15
- end
16
- end
17
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Periodically
4
+ module Model
5
+ def self.included(base)
6
+ base.extend ClassMethods
7
+ end
8
+
9
+ module ClassMethods
10
+ def periodically(symbol, **opts)
11
+ Periodically.register(self, symbol, opts)
12
+ end
13
+ end
14
+ end
15
+ end
data/periodically.gemspec CHANGED
@@ -4,7 +4,7 @@ Gem::Specification.new do |gem|
4
4
 
5
5
  gem.files = `git ls-files | grep -Ev '^(test|myapp|examples)'`.split("\n")
6
6
  gem.name = "periodically"
7
- gem.version = "0.0.1"
7
+ gem.version = "0.0.2"
8
8
  gem.required_ruby_version = ">= 2.5.0"
9
9
 
10
10
  gem.add_dependency "redis", ">= 4.1.0"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: periodically
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - wyozi
@@ -60,10 +60,12 @@ extra_rdoc_files: []
60
60
  files:
61
61
  - ".editorconfig"
62
62
  - Gemfile
63
+ - Gemfile.lock
63
64
  - README.md
65
+ - Rakefile
64
66
  - lib/periodically.rb
65
67
  - lib/periodically/cli.rb
66
- - lib/periodically/condition.rb
68
+ - lib/periodically/debug.rb
67
69
  - lib/periodically/job.rb
68
70
  - lib/periodically/model.rb
69
71
  - lib/periodically/redis.rb
@@ -1,28 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Periodically
4
- module Condition
5
- def self.class()
6
-
7
- end
8
-
9
- def self.evaluate(func)
10
- condition = func.call()
11
-
12
- simple = simple_evaluation(condition)
13
-
14
- # Filter condition to skip
15
- if evaluated.is_a?(ActiveRecord::Base)
16
-
17
- end
18
- end
19
-
20
- private
21
-
22
- def self.simple_evaluation(condition)
23
- row = evaluated.first()
24
- row if !Periodically.redis {|conn| conn.exists("")}
25
- end
26
-
27
- end
28
- end