periodically 0.0.1 → 0.0.2

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: 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