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 +4 -4
- data/.editorconfig +1 -1
- data/Gemfile +14 -5
- data/Gemfile.lock +68 -0
- data/README.md +13 -12
- data/Rakefile +10 -0
- data/lib/periodically.rb +13 -3
- data/lib/periodically/debug.rb +16 -0
- data/lib/periodically/job.rb +10 -9
- data/lib/periodically/model.rb +15 -17
- data/periodically.gemspec +1 -1
- metadata +4 -2
- data/lib/periodically/condition.rb +0 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8606b68187a8ed711211079f83437e183a35b16c896d5e54f8c091717bd099cf
|
4
|
+
data.tar.gz: f30a109baee2a14159db2d8efb08b59a795c4ced31085e12fbc3a36878ef80cc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4a4062005b2f44f31febb25be53f77d1afd765555dba06656456cf882e782c2e889fb8fe2cf6a2346ace47a033be85a2ce798a2cf23e10a437ca877b0f83b46d
|
7
|
+
data.tar.gz: 6020c84dcd0e0829e1d1b3e1c2dcd5fe6cbee482ef66f9be43fb8102bdadb212c9c0301e4f4b02b21fd454a3d235467f8f548bc7f70dbc7fc557bcb917c9d98e
|
data/.editorconfig
CHANGED
data/Gemfile
CHANGED
@@ -1,5 +1,14 @@
|
|
1
|
-
source 'https://rubygems.org'
|
2
|
-
|
3
|
-
gem '
|
4
|
-
gem '
|
5
|
-
gem '
|
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
|
-
|
14
|
+
## Getting started with Rails
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
**Add gem to Gemfile and install**
|
17
|
+
|
18
|
+
`gem 'periodically'` && `bundle install`
|
19
19
|
|
20
|
-
|
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
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"
|
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
|
48
|
+
require "rufus-scheduler"
|
44
49
|
scheduler = Rufus::Scheduler.new
|
45
50
|
|
46
51
|
Periodically.redis { |conn| conn.ping }
|
47
52
|
|
48
|
-
scheduler.interval
|
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
|
+
|
data/lib/periodically/job.rb
CHANGED
@@ -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
|
40
|
-
instance.
|
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:#{
|
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:#{
|
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:#{
|
59
|
+
lock_key = "locks:#{full_instance_key(instance)}"
|
59
60
|
|
60
61
|
Periodically.redis do |conn|
|
61
62
|
conn.multi do |multi|
|
data/lib/periodically/model.rb
CHANGED
@@ -1,17 +1,15 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Periodically
|
4
|
-
module Model
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
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.
|
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.
|
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/
|
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
|