redis-scheduler 0.2 → 0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/README +8 -3
  2. data/lib/redis-scheduler.rb +45 -7
  3. metadata +3 -5
data/README CHANGED
@@ -1,13 +1,14 @@
1
1
  This is a basic chronological scheduler for Redis. It allows you to schedule
2
2
  items to be processed at arbitrary points in time (via #schedule!), and then
3
- to easily retrieve only those items that are due to be processed (via #each!).
3
+ to easily retrieve only those items that are due to be processed (via #each).
4
+
4
5
  Items are represented as strings.
5
6
 
6
7
  It does everything you'd want from a production scheduler:
7
- * You can schedule arbitrary items at arbitrary times.
8
+ * You can schedule items at arbitrary times.
8
9
  * It supports multiple simultaneous readers and writers.
9
10
  * An exception causes the in-process item to be rescheduled at the original time.
10
- * A crash leaves the item in an error queue, from which it can later be recovered.
11
+ * A crash leaves the item in a separate error queue, from which it can later be recovered.
11
12
  * You can iterate over ready items in either blocking or non-blocking mode.
12
13
 
13
14
  In non-blocking mode (the default), #each will iterate only over those work items
@@ -32,6 +33,10 @@ until items are available. In blocking mode, #each will never return.
32
33
  20.06058172: c
33
34
  ... waits forever ...
34
35
 
36
+ == Implementation
37
+
38
+ See http://masanjin.net/blog/using-redis-for-scheduling for some details.
39
+
35
40
  == Bug reports
36
41
 
37
42
  Please file bugs here: https://github.com/wmorgan/redis-scheduler/issues
@@ -5,9 +5,8 @@ class RedisScheduler
5
5
  CAS_DELAY = 0.5 # seconds
6
6
 
7
7
  ## options:
8
- ## namespace: prefix for redis data, e.g. "scheduler/"
9
- ## blocking: whether #each should block or return immediately if
10
- ## there are items to be processed immediately.
8
+ ## * +namespace+: prefix for redis data, e.g. "scheduler/"
9
+ ## * +blocking+: whether #each should block or return immediately if there are items to be processed immediately.
11
10
  ##
12
11
  ## Note that nonblocking mode may still actually block as part of the
13
12
  ## check-and-set semantics, i.e. block during contention from multiple
@@ -35,6 +34,9 @@ class RedisScheduler
35
34
  [@queue, @error_queue, @counter].each { |k| @redis.del k }
36
35
  end
37
36
 
37
+ def size; @redis.zcard @queue end
38
+ def error_queue_size; @redis.llen @error_queue end
39
+
38
40
  ## yields items along with their scheduled times. only returns items
39
41
  ## on or after their scheduled times. items returned as strings. if
40
42
  ## @blocking is false, will stop once there are no more items that can
@@ -42,18 +44,27 @@ class RedisScheduler
42
44
  ## become available (and never terminate).
43
45
  def each
44
46
  while(x = get)
45
- item, at = x
47
+ item, erritem, at = x
46
48
  begin
47
49
  yield item, at
48
50
  rescue Exception # back in the hole!
49
51
  schedule! item, at
50
52
  raise
51
53
  ensure
52
- cleanup! item
54
+ cleanup! erritem
53
55
  end
54
56
  end
55
57
  end
56
58
 
59
+ ## returns an Enumerable of [item, schedule time] pairs, which can be used to
60
+ ## easily iterate over all the items in the queue, in order of earliest- to
61
+ ## latest-scheduled. note that this view is not coordinated with write
62
+ ## operations, and may be inconsistent (e.g. return duplicates, miss items,
63
+ ## etc).
64
+ ##
65
+ ## for these reasons, this operation is mainly useful for debugging purposes.
66
+ def items; ItemEnumerator.new(@redis, @queue) end
67
+
57
68
  private
58
69
 
59
70
  def get; @blocking ? blocking_get : nonblocking_get end
@@ -78,8 +89,8 @@ private
78
89
  throw :cas_retry
79
90
  end
80
91
  item =~ /^\d+:(\S+)$/ or raise InvalidEntryException, item
81
- item = $1
82
- [item, Time.at(at.to_f)]
92
+ original = $1
93
+ [original, item, Time.at(at.to_f)]
83
94
  end
84
95
  end
85
96
  end
@@ -87,4 +98,31 @@ private
87
98
  def cleanup! item
88
99
  @redis.lrem @error_queue, 1, item
89
100
  end
101
+
102
+ ## enumerable for just iterating over everything in the queue
103
+ class ItemEnumerator
104
+ include Enumerable
105
+ def initialize redis, q
106
+ @redis = redis
107
+ @q = q
108
+ end
109
+
110
+ BLOCK_SIZE = 10
111
+ def each
112
+ start = 0
113
+ while start < size
114
+ elements = @redis.zrange @q, start, start + BLOCK_SIZE,
115
+ :withscores => true
116
+ elements.each_slice(2) do |item, at| # isgh
117
+ item =~ /^\d+:(\S+)$/ or raise InvalidEntryException, item
118
+ item = $1
119
+ yield item, Time.at(at.to_f)
120
+ end
121
+ start += elements.size
122
+ end
123
+ end
124
+
125
+ def size; @redis.zcard @q end
126
+ end
127
+
90
128
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redis-scheduler
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.2'
4
+ version: '0.3'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,8 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-04-18 00:00:00.000000000 -07:00
13
- default_executable:
12
+ date: 2012-04-29 00:00:00.000000000 Z
14
13
  dependencies: []
15
14
  description: A basic chronological scheduler for Redis. Add work items to be processed
16
15
  at specific times in the future, and easily retrieve all items that are ready for
@@ -23,7 +22,6 @@ files:
23
22
  - README
24
23
  - COPYING
25
24
  - lib/redis-scheduler.rb
26
- has_rdoc: true
27
25
  homepage: http://gitub.com/wmorgan/redis-scheduler
28
26
  licenses: []
29
27
  post_install_message:
@@ -48,7 +46,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
48
46
  version: '0'
49
47
  requirements: []
50
48
  rubyforge_project:
51
- rubygems_version: 1.6.0
49
+ rubygems_version: 1.8.11
52
50
  signing_key:
53
51
  specification_version: 3
54
52
  summary: A basic chronological scheduler for Redis.