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 +0 -0
- data/lib/memcache_queue.rb +112 -0
- data/memcache_queue.gemspec +15 -0
- metadata +64 -0
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
|
+
|