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 CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- MWYxNDY1MDIxNTJkNTJiMmFkYWQyMWFmZWQ5Y2ZkZjMwMmE1MTkwZQ==
5
- data.tar.gz: !binary |-
6
- MjE0OWFiYjA1NjlkMmE0NjgwMzViMDY4ZjVmYTdhODQzNzdjYjJmMg==
7
- !binary "U0hBNTEy":
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
@@ -1,5 +1,6 @@
1
1
  *.gem
2
2
  *.rbc
3
+ .ruby-*
3
4
  .bundle
4
5
  .config
5
6
  .yardoc
@@ -0,0 +1,10 @@
1
+ rvm:
2
+ - 2.1.0
3
+ cache:
4
+ - bundler
5
+ notifications:
6
+ email:
7
+ - dalibor.nasevic@gmail.com
8
+ services:
9
+ - redis-server
10
+ script: bundle exec rspec spec
data/README.md CHANGED
@@ -1,9 +1,10 @@
1
+ ![Travis status](https://travis-ci.org/madmimi/deferrer.png)
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
@@ -22,4 +22,5 @@ Gem::Specification.new do |spec|
22
22
  spec.add_dependency "multi_json"
23
23
  spec.add_development_dependency "bundler", "~> 1.3"
24
24
  spec.add_development_dependency "rake"
25
+ spec.add_development_dependency "rspec", "~> 2.14.1"
25
26
  end
@@ -4,23 +4,18 @@ module Deferrer
4
4
  LIST_KEY = :deferred_list
5
5
 
6
6
  def run(options = {})
7
- loop_frequency = options[:loop_frequency] || 0.1
8
- logger = options[:logger] || nil
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
- begin
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
- _, item = redis.brpop(key, 0)
37
- decoded_item = decode(item) if item
38
- decoded_item['key'] = key
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
@@ -1,3 +1,3 @@
1
1
  module Deferrer
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -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
- car.upcase
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.flushall
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 "deferrs in given interval" do
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.1
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-03-03 00:00:00.000000000 Z
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.0.0
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: