em-bucketer 0.2.0 → 0.2.1

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,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: aa43207fc878f4d9f0f15851590ec66803f45694
4
- data.tar.gz: 9cd15644641ffccdd96552f45bbc5b420de5a262
3
+ metadata.gz: c433f1cc453123f151e4a89363b6a6ebcb02e991
4
+ data.tar.gz: a541740a352cdc8c3a4e6474d6a7f0d69b4979a2
5
5
  SHA512:
6
- metadata.gz: 7b4ee20c2e7ad8cb933b5a0de2dfea6cd9b05ee7375cd156ea8659feda615890e8a6d52490e63dafb6d71e44b992eb33b066889b207b21efe693862fcff19fd7
7
- data.tar.gz: 96447882b8d6cdf6a20dc62a25f69af698de3708eb523735fcec40ae503edab3237b919ba72aa69ae9861d2350e7ec9b3a0110383eb5e857db439ed075e44a0d
6
+ metadata.gz: fa4fcfa73e8d0311c2534cdd759fd8150a2fc96868faa271b96b26f12a125084822cd131816dd886df66e95ebecc89a0b474ae1297843b3bc5f5c5db5a3de50a
7
+ data.tar.gz: 39cd7430e0855f9048e6294cfa38cf7137d83172a6e5af997c4b7b14b4919bdf411a0d25838336325fe99695b02c7593f232373ad7cc5bee6f08c9f9eed8eefc
@@ -3,7 +3,6 @@ module EventMachine::Bucketer
3
3
  def setup(bucket_threshold_size, bucket_max_age)
4
4
  @bucket_threshold_size = bucket_threshold_size
5
5
  @bucket_max_age = bucket_max_age
6
- @buckets = {}
7
6
  @on_bucket_full_callbacks = []
8
7
  @on_bucket_timeout_callbacks = []
9
8
  @buckets_with_timers = Set.new
@@ -1,10 +1,14 @@
1
- require 'em-bucketer/database'
1
+ require 'em-bucketer/ordered/database'
2
2
 
3
3
  module EventMachine::Bucketer
4
4
  module Database
5
5
  module Hash
6
6
  private
7
7
 
8
+ def setup_db
9
+ @buckets = {}
10
+ end
11
+
8
12
  def bucket_size_from_db(bucket_id, &blk)
9
13
  EM::Completion.new.tap do |c|
10
14
  c.callback(&blk) if block_given?
@@ -6,6 +6,9 @@ module EventMachine::Bucketer
6
6
  module Redis
7
7
  private
8
8
 
9
+ def setup_db
10
+ end
11
+
9
12
  def bucket_size_from_db(bucket_id, &blk)
10
13
  EM::Completion.new.tap do |c|
11
14
  c.callback(&blk) if block_given?
@@ -19,6 +19,7 @@ module EventMachine::Bucketer
19
19
  # can remain before the on_bucket_timed_out is called
20
20
  def initialize(bucket_threshold_size: BUCKET_THRESHOLD_SIZE_DEFAULT, bucket_max_age: BUCKET_MAX_AGE_DEFAULT)
21
21
  setup(bucket_threshold_size, bucket_max_age)
22
+ setup_db
22
23
  end
23
24
  end
24
25
  end
@@ -3,7 +3,6 @@ module EventMachine::Bucketer
3
3
  def setup(bucket_threshold_size, bucket_max_age)
4
4
  @bucket_threshold_size = bucket_threshold_size
5
5
  @bucket_max_age = bucket_max_age
6
- @buckets = {}
7
6
  @on_bucket_full_callbacks = []
8
7
  @on_bucket_timeout_callbacks = []
9
8
  @timers = {}
@@ -6,6 +6,10 @@ module EventMachine::Bucketer
6
6
  module Hash
7
7
  private
8
8
 
9
+ def setup_db
10
+ @buckets = {}
11
+ end
12
+
9
13
  def pop_all_from_db(bucket_id, &blk)
10
14
  EM::Completion.new.tap do |c|
11
15
  c.callback(&blk) if block_given?
@@ -0,0 +1,120 @@
1
+ require 'em-bucketer/ordered/database'
2
+ require 'em-hiredis'
3
+
4
+ module EventMachine::Bucketer
5
+ module Ordered::Database
6
+ module Redis
7
+ private
8
+
9
+ def setup_db
10
+ redis.register_script(:lpopn, <<-END)
11
+ local r = redis.call('lrange', KEYS[1], 0, ARGV[1] - 1)
12
+ redis.call('ltrim', KEYS[1], ARGV[1], -1)
13
+ return r
14
+ END
15
+ redis.register_script(:lpopa, <<-END)
16
+ local r = redis.call('lrange', KEYS[1], 0, - 1)
17
+ redis.call('del', KEYS[1])
18
+ return r
19
+ END
20
+ end
21
+
22
+ def bucket_size_from_db(bucket_id, &blk)
23
+ EM::Completion.new.tap do |c|
24
+ c.callback(&blk) if block_given?
25
+ redis.llen(redis_key(bucket_id)).callback do |len|
26
+ c.succeed len.to_i
27
+ end.errback do |e|
28
+ c.fail e
29
+ end
30
+ end
31
+ end
32
+
33
+ def add_item_to_db(bucket_id, item, &blk)
34
+ EM::Completion.new.tap do |c|
35
+ c.callback(&blk) if block_given?
36
+ redis.rpush(redis_key(bucket_id), Marshal.dump(item)).callback do
37
+ add_to_known_buckets(bucket_id).callback do
38
+ c.succeed
39
+ end.errback do |e|
40
+ c.fail e
41
+ end
42
+ end.errback do |e|
43
+ c.fail e
44
+ end
45
+ end
46
+ end
47
+
48
+ def pop_all_from_db(bucket_id, &blk)
49
+ EM::Completion.new.tap do |c|
50
+ c.callback(&blk) if block_given?
51
+ redis.lpopa([redis_key(bucket_id)]).callback do |data|
52
+ bucket = data.map { |d| Marshal.load(d) }
53
+ c.succeed bucket
54
+ end.errback do |e|
55
+ c.fail e
56
+ end
57
+ end
58
+ end
59
+
60
+ def pop_count_from_db(bucket_id, count, &blk)
61
+ EM::Completion.new.tap do |c|
62
+ c.callback(&blk) if block_given?
63
+ redis.lpopn([redis_key(bucket_id)], count).callback do |data|
64
+ bucket = data.map { |d| Marshal.load(d) }
65
+ c.succeed bucket
66
+ end.errback do |e|
67
+ c.fail e
68
+ end
69
+ end
70
+ end
71
+
72
+ def get_bucket_from_db(bucket_id, &blk)
73
+ EM::Completion.new.tap do |c|
74
+ c.callback(&blk) if block_given?
75
+ redis.lrange(redis_key(bucket_id), 0, -1).callback do |data|
76
+ bucket = data.map { |d| Marshal.load(d) }
77
+ c.succeed bucket
78
+ end.errback do |e|
79
+ c.fail e
80
+ end
81
+ end
82
+ end
83
+
84
+ def empty_bucket_in_db(bucket_id, &blk)
85
+ EM::Completion.new.tap do |c|
86
+ c.callback(&blk) if block_given?
87
+ redis.del(redis_key(bucket_id)).callback do
88
+ remove_from_known_buckets(bucket_id).callback do
89
+ c.succeed
90
+ end.errback do |e|
91
+ c.fail e
92
+ end
93
+ end.errback do |e|
94
+ c.fail e
95
+ end
96
+ end
97
+ end
98
+
99
+ def known_buckets(&blk)
100
+ redis.smembers(redis_known_buckets_key, &blk)
101
+ end
102
+
103
+ def add_to_known_buckets(bucket_id, &blk)
104
+ redis.sadd(redis_known_buckets_key, bucket_id, &blk)
105
+ end
106
+
107
+ def remove_from_known_buckets(bucket_id, &blk)
108
+ redis.srem(redis_known_buckets_key, bucket_id, &blk)
109
+ end
110
+
111
+ def redis_key(bucket_id)
112
+ "em_bucketer_ordered:#{redis_prefix}:#{bucket_id}"
113
+ end
114
+
115
+ def redis_known_buckets_key
116
+ "em_bucketer_ordered_known_buckets:#{redis_prefix}"
117
+ end
118
+ end
119
+ end
120
+ end
@@ -19,6 +19,7 @@ module EventMachine::Bucketer
19
19
  # can remain before the on_bucket_timed_out is called
20
20
  def initialize(bucket_threshold_size: BUCKET_THRESHOLD_SIZE_DEFAULT, bucket_max_age: BUCKET_MAX_AGE_DEFAULT)
21
21
  setup(bucket_threshold_size, bucket_max_age)
22
+ setup_db
22
23
  end
23
24
  end
24
25
  end
@@ -0,0 +1,69 @@
1
+ require 'eventmachine'
2
+ require 'em-bucketer/ordered/database/redis'
3
+ require 'em-bucketer/ordered/base'
4
+
5
+ module EventMachine::Bucketer
6
+ class Ordered::Redis
7
+ include Ordered::Database::Redis
8
+ include Ordered::Base
9
+
10
+ BUCKET_THRESHOLD_SIZE_DEFAULT = 1000
11
+ BUCKET_MAX_AGE_DEFAULT = 3600
12
+
13
+ # Creates a new redis Bucketer with the requested
14
+ # configurations.
15
+ # *NOTE* The redis bucketer uses Marshal to store
16
+ # the objects in redis. This puts limitations on
17
+ # the data that cannot be stored in these buckets.
18
+ # For example you cannot store an object that
19
+ # references a proc as an instance variable.
20
+ #
21
+ # The redis bucketer also sets all timers on
22
+ # startup for buckets already in the redis
23
+ # database. This ensures that even if your
24
+ # app is restarted the previous timers will still
25
+ # get set and you won't ever lose a bucket.
26
+ #
27
+ # @param redis_prefix [String] The prefix for the
28
+ # bucket in redis. This is necessary because you
29
+ # may want to have multiple bucketers using one
30
+ # redis instance and you don't want them conflicting.
31
+ # Also this can't just be random because the whole
32
+ # point of the redis bucketer is that you can restart
33
+ # your app and get back the same bucketer without any
34
+ # data loss.
35
+ # @param bucket_threshold_size [Integer] the max size of the bucket
36
+ # after which the on_bucket_full callback is called
37
+ # @param bucket_max_age [Integer] max number of seconds a bucket
38
+ # can remain before the on_bucket_timed_out is called
39
+ def initialize(redis_prefix, bucket_threshold_size: BUCKET_THRESHOLD_SIZE_DEFAULT, bucket_max_age: BUCKET_MAX_AGE_DEFAULT)
40
+ @redis = EM::Hiredis.connect
41
+ @redis_prefix = redis_prefix
42
+ setup(bucket_threshold_size, bucket_max_age)
43
+ setup_db
44
+ set_timers
45
+ end
46
+
47
+ def set_timers
48
+ known_buckets.callback do |bucket_ids|
49
+ bucket_ids.each do |bucket_id|
50
+ add_timer_if_first(bucket_id)
51
+ end
52
+ end.errback do |e|
53
+ # I think this is okay since it will only happen when
54
+ # you are initializing the bucketer so it will hopefully
55
+ # bring the issue to your attention on startup. I
56
+ # couldn't actually pass this error back through to
57
+ # anyone so I needed to raise it. It is also a bad
58
+ # exception since it means you are not properly reloading
59
+ # your buckets from redis
60
+ raise e
61
+ end
62
+ end
63
+
64
+ private
65
+
66
+ # Used by Database::Redis
67
+ attr_reader :redis_prefix, :redis
68
+ end
69
+ end
@@ -5,4 +5,4 @@ end
5
5
 
6
6
  require 'eventmachine'
7
7
  require 'em-bucketer/ordered/in_memory'
8
- #require 'em-bucketer/ordered/redis'
8
+ require 'em-bucketer/ordered/redis'
@@ -40,6 +40,7 @@ module EventMachine::Bucketer
40
40
  @redis = EM::Hiredis.connect
41
41
  @redis_prefix = redis_prefix
42
42
  setup(bucket_threshold_size, bucket_max_age)
43
+ setup_db
43
44
  set_timers
44
45
  end
45
46
 
@@ -1,5 +1,5 @@
1
1
  module EventMachine
2
2
  module Bucketer
3
- VERSION = "0.2.0"
3
+ VERSION = "0.2.1"
4
4
  end
5
5
  end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+ require 'em-bucketer/ordered'
3
+ require 'redis'
4
+
5
+ describe EventMachine::Bucketer::Ordered::Redis do
6
+ let(:prefix) { "test_prefix" }
7
+ before(:each) do
8
+ redis = Redis.new
9
+ redis.keys("em_bucketer_ordered:#{prefix}:*").each do |k|
10
+ redis.del(k)
11
+ end
12
+ redis.del("em_bucketer_ordered_known_buckets:#{prefix}")
13
+ end
14
+
15
+ it_behaves_like "an ordered bucketer" do
16
+ let(:bucketer) { EM::Bucketer::Ordered::Redis.new(prefix, :bucket_threshold_size => 5) }
17
+ end
18
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: em-bucketer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Heycock
@@ -147,13 +147,16 @@ files:
147
147
  - lib/em-bucketer/ordered/base.rb
148
148
  - lib/em-bucketer/ordered/database.rb
149
149
  - lib/em-bucketer/ordered/database/hash.rb
150
+ - lib/em-bucketer/ordered/database/redis.rb
150
151
  - lib/em-bucketer/ordered/in_memory.rb
152
+ - lib/em-bucketer/ordered/redis.rb
151
153
  - lib/em-bucketer/redis.rb
152
154
  - lib/em-bucketer/version.rb
153
155
  - spec/em_bucketer_examples.rb
154
156
  - spec/em_bucketer_ordered_examples.rb
155
157
  - spec/in_memory_ordered_spec.rb
156
158
  - spec/in_memory_spec.rb
159
+ - spec/redis_ordered_spec.rb
157
160
  - spec/redis_spec.rb
158
161
  - spec/spec_helper.rb
159
162
  - spec/spec_methods.rb
@@ -187,6 +190,7 @@ test_files:
187
190
  - spec/em_bucketer_ordered_examples.rb
188
191
  - spec/in_memory_ordered_spec.rb
189
192
  - spec/in_memory_spec.rb
193
+ - spec/redis_ordered_spec.rb
190
194
  - spec/redis_spec.rb
191
195
  - spec/spec_helper.rb
192
196
  - spec/spec_methods.rb