deferrer 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 +6 -14
- data/.gitignore +1 -0
- data/.travis.yml +10 -0
- data/README.md +10 -2
- data/deferrer.gemspec +1 -0
- data/lib/deferrer/deferral.rb +25 -15
- data/lib/deferrer/version.rb +1 -1
- data/spec/deferrer/deferral_spec.rb +59 -3
- metadata +31 -15
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
metadata.gz: !binary |-
|
9
|
-
NjMzNmU0ZmVjOWRiYWVhODY1YzU4MmY5OTRmNzNhYTdiNTMwMmUzMTdlOTE3
|
10
|
-
NWIxNjI4MGI1ODkxNDVhODFhYjJjMDkyMzNlYTg1MDVkODU2NzY1YTMyMzEx
|
11
|
-
NGUxNzNjMjY5MWRjZDBhNDMwYzQ2YjZhMjkzN2EwMTg1ZDNmZjc=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
YWEzOTI3NWVjNjk3OTVjMDdjOGM4NGU1ZTA2ZDFmOWE3OGE2NDM0NTJiZjkx
|
14
|
-
YTY5Y2Q1NmUzOTgzNjE0ZjZjNjY3YjYzZDlmNDAxNWJjY2Y2ZjZlNmM1Zjdm
|
15
|
-
NGNjM2E5ZmU5NTEwY2NjZGE3YjE3NzliNDI5YjBjZjZmYTNlN2Y=
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 3177ff9473fe3ddecdc6579a2adcde3fa02112f5
|
4
|
+
data.tar.gz: de0bbbd3540ec14e50061ed917d633dd27be62d1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5db8302690c0707b3d0ce6ae0ef03c87e26be05024565bd579121deb222cc4987788fd832d7366842a1d56e32acaea1abfc9702fef965c5c513e05427522f04c
|
7
|
+
data.tar.gz: f3cd63d60f6d37c4275781fb58a0ace53dcb730b5af152744de7059000ec4d2f4b9fc84785e5bbe45efc05d51ace50bf893a84938b18b8ddee1d1ee99f8620a2
|
data/.gitignore
CHANGED
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
+

|
2
|
+
|
1
3
|
# Deferrer
|
2
4
|
|
3
5
|
Defer executions and run only the last update at the scheduled time
|
4
6
|
|
5
7
|
|
6
|
-
|
7
8
|
## Installation
|
8
9
|
|
9
10
|
Add this line to your application's Gemfile:
|
@@ -38,7 +39,14 @@ Define deferrer class (must have perform class method)
|
|
38
39
|
|
39
40
|
Start a worker process. It needs to have redis configured and access to deferrer classes.
|
40
41
|
|
41
|
-
Deferrer.run
|
42
|
+
Deferrer.run(options = {})
|
43
|
+
|
44
|
+
# Following `options` are available:
|
45
|
+
# loop_frequency - sleep between loops, default to 0.1 seconds
|
46
|
+
# logger - logging mechanism, needs to respond to `info` and `error`
|
47
|
+
# before_each - callback to run before processing an item, needs to respond to `call`
|
48
|
+
# after_each - callback to run after processing an item, needs to respond to `call`
|
49
|
+
# single_run - process items only for a single loop, useful for testing
|
42
50
|
|
43
51
|
|
44
52
|
Defer some executions
|
data/deferrer.gemspec
CHANGED
data/lib/deferrer/deferral.rb
CHANGED
@@ -4,23 +4,18 @@ module Deferrer
|
|
4
4
|
LIST_KEY = :deferred_list
|
5
5
|
|
6
6
|
def run(options = {})
|
7
|
-
loop_frequency = options
|
8
|
-
logger
|
7
|
+
loop_frequency = options.fetch(:loop_frequency, 0.1)
|
8
|
+
logger = options.fetch(:logger, nil)
|
9
|
+
before_each = options.fetch(:before_each, nil)
|
10
|
+
after_each = options.fetch(:after_each, nil)
|
11
|
+
single_run = options.fetch(:single_run, false)
|
9
12
|
|
10
13
|
loop do
|
11
14
|
while item = next_item
|
12
|
-
|
13
|
-
klass = constantize(item['class'])
|
14
|
-
args = item['args']
|
15
|
-
|
16
|
-
logger.info("Executing: #{item['key']}") if logger
|
17
|
-
|
18
|
-
klass.send(:perform, *args)
|
19
|
-
rescue Exception => e
|
20
|
-
logger.error("Error: #{e.class}: #{e.detail}") if logger
|
21
|
-
end
|
15
|
+
process_item(item, logger, before_each, after_each)
|
22
16
|
end
|
23
17
|
|
18
|
+
break if single_run
|
24
19
|
sleep loop_frequency
|
25
20
|
end
|
26
21
|
end
|
@@ -33,9 +28,11 @@ module Deferrer
|
|
33
28
|
key = redis.zrangebyscore(LIST_KEY, '-inf', score, :limit => [0, 1]).first
|
34
29
|
|
35
30
|
if key
|
36
|
-
|
37
|
-
|
38
|
-
|
31
|
+
item = redis.rpop(key)
|
32
|
+
if item
|
33
|
+
decoded_item = decode(item)
|
34
|
+
decoded_item['key'] = key
|
35
|
+
end
|
39
36
|
|
40
37
|
remove(key)
|
41
38
|
end
|
@@ -70,6 +67,19 @@ module Deferrer
|
|
70
67
|
end
|
71
68
|
|
72
69
|
private
|
70
|
+
def process_item(item, logger, before_each, after_each)
|
71
|
+
before_each.call if before_each
|
72
|
+
klass = constantize(item['class'])
|
73
|
+
args = item['args']
|
74
|
+
|
75
|
+
logger.info("Executing: #{item['key']}") if logger
|
76
|
+
|
77
|
+
klass.send(:perform, *args)
|
78
|
+
after_each.call if after_each
|
79
|
+
rescue Exception => e
|
80
|
+
logger.error("Error: #{e.class}: #{e.message}") if logger
|
81
|
+
end
|
82
|
+
|
73
83
|
def build_item(klass, args)
|
74
84
|
{'class' => klass.to_s, 'args' => args}
|
75
85
|
end
|
data/lib/deferrer/version.rb
CHANGED
@@ -1,8 +1,24 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'timeout'
|
2
3
|
|
3
4
|
class CarDeferrer
|
4
5
|
def self.perform(car)
|
5
|
-
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.callback
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class Logger
|
13
|
+
def self.info(message)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.error(message)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class InvalidLogger
|
21
|
+
def self.error(message)
|
6
22
|
end
|
7
23
|
end
|
8
24
|
|
@@ -14,7 +30,39 @@ describe Deferrer::Deferral do
|
|
14
30
|
let(:list_key) { Deferrer::Deferral::LIST_KEY }
|
15
31
|
|
16
32
|
before :each do
|
17
|
-
redis.
|
33
|
+
redis.flushdb
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "run" do
|
37
|
+
it "processes jobs" do
|
38
|
+
CarDeferrer.should_receive(:perform).with(car)
|
39
|
+
Deferrer.defer_in(-1, identifier, CarDeferrer, car)
|
40
|
+
Deferrer.run(single_run: true)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "logs info messages if logger provided" do
|
44
|
+
Logger.should_receive(:info).with("Executing: deferred:#{identifier}")
|
45
|
+
Deferrer.defer_in(-1, identifier, CarDeferrer, car)
|
46
|
+
Deferrer.run(single_run: true, logger: Logger)
|
47
|
+
end
|
48
|
+
|
49
|
+
it "logs error messages if logger provided" do
|
50
|
+
InvalidLogger.should_receive(:error).with("Error: NoMethodError: undefined method `info' for InvalidLogger:Class")
|
51
|
+
Deferrer.defer_in(-1, identifier, CarDeferrer, car)
|
52
|
+
Deferrer.run(single_run: true, logger: InvalidLogger)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "runs before callback" do
|
56
|
+
CarDeferrer.should_receive(:callback)
|
57
|
+
Deferrer.defer_in(-1, identifier, CarDeferrer, car)
|
58
|
+
Deferrer.run(single_run: true, before_each: Proc.new { CarDeferrer.callback })
|
59
|
+
end
|
60
|
+
|
61
|
+
it "runs after callback" do
|
62
|
+
CarDeferrer.should_receive(:callback)
|
63
|
+
Deferrer.defer_in(-1, identifier, CarDeferrer, car)
|
64
|
+
Deferrer.run(single_run: true, after_each: Proc.new { CarDeferrer.callback })
|
65
|
+
end
|
18
66
|
end
|
19
67
|
|
20
68
|
describe ".defer_at" do
|
@@ -25,7 +73,7 @@ describe Deferrer::Deferral do
|
|
25
73
|
redis.exists(Deferrer.item_key(identifier)).should be_true
|
26
74
|
end
|
27
75
|
|
28
|
-
it "
|
76
|
+
it "defers in given interval" do
|
29
77
|
Deferrer.defer_in(1, identifier, CarDeferrer, car)
|
30
78
|
|
31
79
|
redis.zrangebyscore(list_key, '-inf', (Time.now + 1).to_f, :limit => [0, 1]).first.should_not be_nil
|
@@ -73,5 +121,13 @@ describe Deferrer::Deferral do
|
|
73
121
|
redis.exists(Deferrer.item_key(identifier)).should be_false
|
74
122
|
Deferrer.next_item.should be_nil
|
75
123
|
end
|
124
|
+
|
125
|
+
it "doesn't block on empty lists" do
|
126
|
+
Deferrer.defer_in(-1, identifier, CarDeferrer, car)
|
127
|
+
redis.del Deferrer.item_key(identifier)
|
128
|
+
|
129
|
+
Timeout::timeout(2) { Deferrer.next_item.should be_nil }
|
130
|
+
redis.zrangebyscore(list_key, '-inf', 'inf', :limit => [0, 1]).first.should be_nil
|
131
|
+
end
|
76
132
|
end
|
77
133
|
end
|
metadata
CHANGED
@@ -1,71 +1,85 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: deferrer
|
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
|
- Dalibor Nasevic
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-07-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: multi_json
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: bundler
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - ~>
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '1.3'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - ~>
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '1.3'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rake
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- -
|
66
|
+
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 2.14.1
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 2.14.1
|
69
83
|
description: Defer executions and run only the last update
|
70
84
|
email:
|
71
85
|
- dalibor.nasevic@gmail.com
|
@@ -73,8 +87,9 @@ executables: []
|
|
73
87
|
extensions: []
|
74
88
|
extra_rdoc_files: []
|
75
89
|
files:
|
76
|
-
- .gitignore
|
77
|
-
- .rspec
|
90
|
+
- ".gitignore"
|
91
|
+
- ".rspec"
|
92
|
+
- ".travis.yml"
|
78
93
|
- Gemfile
|
79
94
|
- LICENSE.txt
|
80
95
|
- README.md
|
@@ -101,20 +116,21 @@ require_paths:
|
|
101
116
|
- lib
|
102
117
|
required_ruby_version: !ruby/object:Gem::Requirement
|
103
118
|
requirements:
|
104
|
-
- -
|
119
|
+
- - ">="
|
105
120
|
- !ruby/object:Gem::Version
|
106
121
|
version: '0'
|
107
122
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
108
123
|
requirements:
|
109
|
-
- -
|
124
|
+
- - ">="
|
110
125
|
- !ruby/object:Gem::Version
|
111
126
|
version: '0'
|
112
127
|
requirements: []
|
113
128
|
rubyforge_project:
|
114
|
-
rubygems_version: 2.
|
129
|
+
rubygems_version: 2.2.0
|
115
130
|
signing_key:
|
116
131
|
specification_version: 4
|
117
132
|
summary: Defer executions and run only the last update at the scheduled time
|
118
133
|
test_files:
|
119
134
|
- spec/deferrer/deferral_spec.rb
|
120
135
|
- spec/spec_helper.rb
|
136
|
+
has_rdoc:
|