coderrr-memcache_queue 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown ADDED
File without changes
@@ -0,0 +1,112 @@
1
+ require 'rubygems'
2
+ require 'memcache'
3
+
4
+ # It's your job to catch any signals relating to process termination
5
+ # (INT, TERM, etc.) and call the shutdown method on each worker. If
6
+ # this isn't done you run the risk of losing messages.
7
+ class MemcacheQueue
8
+ class ShutdownError < StandardError; end
9
+
10
+ attr_accessor :add_timeout
11
+
12
+ def initialize(name, *args)
13
+ @name = name or raise ArgumentError, "Must specify a unique name for each worker"
14
+ @client = MemCache.new *args
15
+ @first_key = state(:get, name)
16
+ @add_timeout = 10
17
+ end
18
+
19
+ def create_queue
20
+ @client.add('latest_added', '0', 0, true)
21
+ @client.add('latest_read', '0', 0, true)
22
+ end
23
+
24
+ # ! lost message potential !
25
+ # If it takes more than add_timeout seconds from the time incr
26
+ # returns to the time the message is add()ed to memcache the message _could_
27
+ # be lost.
28
+ def add_msg(msg)
29
+ raise ShutdownError if @shutdown
30
+
31
+ begin
32
+ latest_msg ||= @client.incr('latest_added')
33
+ @client.add(latest_msg.to_s, msg)
34
+ @client.set("added_#{latest_msg}", true)
35
+ rescue Exception
36
+ warn "Error on add: #{$!.inspect}, retrying"
37
+ sleep 1
38
+ retry
39
+ end
40
+ end
41
+
42
+ # ! lost message potential !
43
+ # If we die between incr and state(:set) the message _will_ be
44
+ # lost. This would have to be due to hard process kill or other like events.
45
+ def get_msg
46
+ raise ShutdownError if @shutdown
47
+
48
+ if key = @first_key
49
+ @first_key = nil
50
+ else
51
+ key = @client.incr('latest_read').to_s
52
+ end
53
+
54
+ start_time = Time.now
55
+ loop do
56
+ begin
57
+ if msg = @client.get(key)
58
+ begin
59
+ @client.delete(key)
60
+ rescue Exception
61
+ warn "Error while deleting key #{$!.inspect}"
62
+ end
63
+ return msg
64
+ end
65
+ rescue Exception
66
+ warn "Error on get, #{$!.inspect}, retrying"
67
+ end
68
+ state(:set, key) unless @state_set
69
+ raise ShutdownError if @shutdown
70
+ return nil if (Time.now - start_time) > @add_timeout and failed_add?(key)
71
+ sleep 1
72
+ start_time = Time.now if msgs_left(true) < 0
73
+ end
74
+ ensure
75
+ state(:delete, key) if @state_set and ! @shutdown
76
+ end
77
+
78
+ def msgs_left(neg_value = false)
79
+ latest_added = @client.get('latest_added', true).to_i
80
+ latest_read = @client.get('latest_read', true).to_i
81
+
82
+ # check for 64bit boundary crossing
83
+ if latest_added > 2**63 and latest_read < 2**62
84
+ latest_read += 2**64
85
+ elsif latest_read > 2**63 and latest_added < 2**62
86
+ latest_added += 2**64
87
+ end
88
+
89
+ diff = latest_added - latest_read
90
+ neg_value ? diff : [0, diff].max
91
+ end
92
+
93
+ def shutdown
94
+ @shutdown = true
95
+ end
96
+
97
+ private
98
+
99
+ def failed_add?(key)
100
+ msgs_left(true) >= 0 and ! @client.get("added_#{key}")
101
+ end
102
+
103
+ def state(action, key = nil)
104
+ return @client.get("state_#@name") if action == :get
105
+ @client.send(action, "state_#@name", key)
106
+ @state_set = (action == :set)
107
+ rescue Exception
108
+ warn "Error on #{action} state, #{$!.inspect}, retrying"
109
+ sleep 1
110
+ retry
111
+ end
112
+ end
@@ -0,0 +1,15 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "memcache_queue"
3
+ s.version = "0.0.1"
4
+ s.summary = "memcached based queue"
5
+ s.email = "coderrr.contact@gmail.com"
6
+ s.homepage = "http://github.com/coderrr/memcache_queue"
7
+ s.description = "simple message queue which requires only this client and a memcached server"
8
+ s.authors = ["coderrr"]
9
+ s.files = [
10
+ "README.markdown",
11
+ "memcache_queue.gemspec",
12
+ "lib/memcache_queue.rb"
13
+ ]
14
+ s.add_dependency("memcache-client", [">= 1.5.0"])
15
+ end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: coderrr-memcache_queue
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - coderrr
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-02-13 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: memcache-client
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.5.0
24
+ version:
25
+ description: simple message queue which requires only this client and a memcached server
26
+ email: coderrr.contact@gmail.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files: []
32
+
33
+ files:
34
+ - README.markdown
35
+ - memcache_queue.gemspec
36
+ - lib/memcache_queue.rb
37
+ has_rdoc: false
38
+ homepage: http://github.com/coderrr/memcache_queue
39
+ post_install_message:
40
+ rdoc_options: []
41
+
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: "0"
49
+ version:
50
+ required_rubygems_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: "0"
55
+ version:
56
+ requirements: []
57
+
58
+ rubyforge_project:
59
+ rubygems_version: 1.2.0
60
+ signing_key:
61
+ specification_version: 2
62
+ summary: memcached based queue
63
+ test_files: []
64
+