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