agis 0.2.7
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 +7 -0
- data/lib/agis.rb +287 -0
- metadata +73 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6c2efcb1eba59940bd4c9fa4c63baa465d2324a7
|
4
|
+
data.tar.gz: 936b33de7cfcdcb35eba8d0cf8400472968383fc
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b598596dc39f627f3efdc55ef62001a885cf59fcb930710f30523289dc1bb198558ad4641aeeec3b3fd5e81a3c307d2b890b31256e7844fcdea5d6370736c77e
|
7
|
+
data.tar.gz: 47ff87901ca0673f24085843de435f136283d5b8f234ccc1fcef7d0957ff4ee4392c4e7b2b77c48ca75b1110c8850fb9a12dfc35bde28dbf3247a83a6d603775
|
data/lib/agis.rb
ADDED
@@ -0,0 +1,287 @@
|
|
1
|
+
module Agis
|
2
|
+
require 'redis'
|
3
|
+
require 'redis-lock'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
# called whenever a parameter in the queue is of type method
|
7
|
+
# this is unusual behavior
|
8
|
+
class MethodCallInParameters < StandardError
|
9
|
+
end
|
10
|
+
|
11
|
+
class AgisRetryAttemptsExceeded < StandardError
|
12
|
+
end
|
13
|
+
|
14
|
+
class NoAgisIDAvailable < StandardError
|
15
|
+
end
|
16
|
+
|
17
|
+
class RedisLockExpired < StandardError
|
18
|
+
end
|
19
|
+
|
20
|
+
class MessageBoxEmpty < StandardError
|
21
|
+
end
|
22
|
+
|
23
|
+
# the name of the key used for the Agis message box in Redis
|
24
|
+
# the lock is this string followed by ".LOCK"
|
25
|
+
def agis_mailbox
|
26
|
+
begin
|
27
|
+
mid = self.agis_id
|
28
|
+
rescue NoMethodError
|
29
|
+
end
|
30
|
+
begin
|
31
|
+
mid ||= self.id
|
32
|
+
rescue NoMethodError
|
33
|
+
end
|
34
|
+
raise NoAgisIDAvailable unless mid
|
35
|
+
a = "AGIS TERMINAL : " + self.class.to_s + " : " + mid.to_s
|
36
|
+
end
|
37
|
+
|
38
|
+
def agis_aconv(v)
|
39
|
+
a = ""
|
40
|
+
case v
|
41
|
+
when String
|
42
|
+
a = "s:" + v
|
43
|
+
when Symbol
|
44
|
+
a = "s:" + v.to_s
|
45
|
+
when Integer
|
46
|
+
a = "i:" + v.to_s
|
47
|
+
when Hash
|
48
|
+
a = "h:" + v.to_json.to_s
|
49
|
+
when Array
|
50
|
+
a = "a:" + v.to_json.to_s
|
51
|
+
when Float
|
52
|
+
a = "d:" + v.to_s
|
53
|
+
when TrueClass
|
54
|
+
a = "t:"
|
55
|
+
when FalseClass
|
56
|
+
a = "f:"
|
57
|
+
when NilClass
|
58
|
+
a = "n:"
|
59
|
+
else
|
60
|
+
a = "h:" + v.to_json.to_s
|
61
|
+
end
|
62
|
+
return a
|
63
|
+
end
|
64
|
+
|
65
|
+
def agis_fconv(v)
|
66
|
+
case v[0..1]
|
67
|
+
when "s:"
|
68
|
+
v[2..-1]
|
69
|
+
when "i:"
|
70
|
+
v[2..-1].to_i
|
71
|
+
when "h:"
|
72
|
+
JSON.parse!(v[2..-1], symbolize_names: false)
|
73
|
+
when "a:"
|
74
|
+
JSON.parse!(v[2..-1], symbolize_names: false)
|
75
|
+
when "d:"
|
76
|
+
v[2..-1].to_f
|
77
|
+
when "t:"
|
78
|
+
true
|
79
|
+
when "f:"
|
80
|
+
false
|
81
|
+
when "n:"
|
82
|
+
nil
|
83
|
+
when "m:"
|
84
|
+
raise MethodCallInParameters
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# create a method with no parameters
|
89
|
+
def agis_defm0(name, timeout=nil, &b)
|
90
|
+
@agis_methods ||= Hash.new
|
91
|
+
@agis_methods[name] = [0, b, timeout]
|
92
|
+
end
|
93
|
+
|
94
|
+
# create a method with one parameter
|
95
|
+
def agis_defm1(name, timeout=nil, &b)
|
96
|
+
@agis_methods ||= Hash.new
|
97
|
+
@agis_methods[name] = [1, b, timeout]
|
98
|
+
end
|
99
|
+
|
100
|
+
# create a method with two parameters
|
101
|
+
def agis_defm2(name, timeout=nil, &b)
|
102
|
+
@agis_methods ||= Hash.new
|
103
|
+
@agis_methods[name] = [2, b, timeout]
|
104
|
+
end
|
105
|
+
|
106
|
+
# create a method with three parameters
|
107
|
+
def agis_defm3(name, timeout=nil, &b)
|
108
|
+
@agis_methods ||= Hash.new
|
109
|
+
@agis_methods[name] = [3, b, timeout]
|
110
|
+
end
|
111
|
+
|
112
|
+
# alias for agis_defm3
|
113
|
+
def agis_def(name, timeout=nil, &b)
|
114
|
+
agis_defm3(name, timeout, b)
|
115
|
+
end
|
116
|
+
|
117
|
+
def pretty_exception(args, e)
|
118
|
+
ret = []
|
119
|
+
ret << "Agis method call failed: " + args.to_s
|
120
|
+
ret << " " + e.class.to_s
|
121
|
+
e.backtrace.each do |v|
|
122
|
+
ret << v.to_s
|
123
|
+
end
|
124
|
+
ret
|
125
|
+
end
|
126
|
+
|
127
|
+
def popfive(redis)
|
128
|
+
redis.multi do
|
129
|
+
redis.lpop self.agis_mailbox
|
130
|
+
redis.lpop self.agis_mailbox
|
131
|
+
redis.lpop self.agis_mailbox
|
132
|
+
redis.lpop self.agis_mailbox
|
133
|
+
redis.lpop self.agis_mailbox
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def agis_boxlock
|
138
|
+
self.agis_mailbox + ".LOCK"
|
139
|
+
end
|
140
|
+
|
141
|
+
def agis_returnbox
|
142
|
+
self.agis_mailbox + ".RETN"
|
143
|
+
end
|
144
|
+
|
145
|
+
def agis_chew(redis, lock)
|
146
|
+
args = redis.lrange(self.agis_mailbox, 0, 4)
|
147
|
+
mni = args[0]
|
148
|
+
if(mni and mni[0..1] == "m:")
|
149
|
+
# don't do any signatures twice ever
|
150
|
+
lusig = args[4][2..-1]
|
151
|
+
#puts lusig
|
152
|
+
if redis.hget self.agis_returnbox, lusig
|
153
|
+
popfive redis
|
154
|
+
return nil
|
155
|
+
end
|
156
|
+
mn = mni[2..-1]
|
157
|
+
mc = @agis_methods[mn.to_sym][0]
|
158
|
+
meti = @agis_methods[mn.to_sym][1]
|
159
|
+
case meti
|
160
|
+
when Proc
|
161
|
+
met = meti
|
162
|
+
when Symbol
|
163
|
+
met = self.method(meti)
|
164
|
+
when NilClass
|
165
|
+
met = self.method(mn.to_sym) # when proc is Nil, call the class methods all the same
|
166
|
+
end
|
167
|
+
|
168
|
+
begin
|
169
|
+
#raise Agis::RedisLockExpired if lock.stale_key?
|
170
|
+
#begin
|
171
|
+
# lock.extend_life (@agis_methods[mn.to_sym][2] or 5)
|
172
|
+
#rescue Redis::Lock::LockNotAcquired
|
173
|
+
# raise Agis::RedisLockExpired
|
174
|
+
#end
|
175
|
+
case mc
|
176
|
+
when 0
|
177
|
+
ret = agis_aconv(met.call())
|
178
|
+
when 1
|
179
|
+
ret = agis_aconv(met.call(agis_fconv(args[1])))
|
180
|
+
when 2
|
181
|
+
ret = agis_aconv(met.call(agis_fconv(args[1]), agis_fconv(args[2])))
|
182
|
+
when 3
|
183
|
+
ret = agis_aconv(met.call(agis_fconv(args[1]), agis_fconv(args[2]), agis_fconv(args[3])))
|
184
|
+
end
|
185
|
+
redis.multi do
|
186
|
+
redis.hset self.agis_returnbox, lusig, ret
|
187
|
+
popfive redis
|
188
|
+
end
|
189
|
+
return :next
|
190
|
+
rescue Agis::RedisLockExpired => e
|
191
|
+
puts "Agis lock expired for " + args.to_s if (@agis_debugmode == true)
|
192
|
+
# popfive redis
|
193
|
+
return :relock
|
194
|
+
rescue => e
|
195
|
+
#puts "feck"
|
196
|
+
lock.unlock
|
197
|
+
raise e
|
198
|
+
end
|
199
|
+
elsif not mni
|
200
|
+
return :empty
|
201
|
+
else
|
202
|
+
puts "AGIS error: Unrecognized line!" + mni.to_s
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def agis_try_usig(redis, usig)
|
207
|
+
mayb = redis.hget self.agis_returnbox, usig
|
208
|
+
if mayb
|
209
|
+
redis.hdel self.agis_returnbox, usig
|
210
|
+
return mayb
|
211
|
+
else
|
212
|
+
return nil
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def _agis_crunch(redis, usig)
|
217
|
+
loop do
|
218
|
+
redis.lock(self.agis_boxlock, life: 10) do |lock|
|
219
|
+
a = agis_chew(redis, lock)
|
220
|
+
next if lock.stale_key?
|
221
|
+
u = agis_try_usig(redis, usig)
|
222
|
+
if a == :empty
|
223
|
+
raise Agis::MessageBoxEmpty unless u
|
224
|
+
end
|
225
|
+
return agis_fconv(u) if u
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
# Get method in the format
|
231
|
+
# [arity, method body]
|
232
|
+
def agis_method(name)
|
233
|
+
@agis_methods[name]
|
234
|
+
end
|
235
|
+
|
236
|
+
# Push a call and ncrunch immediately
|
237
|
+
# this returns the last return value from the queue
|
238
|
+
def agis_call(redis, name, arg1=nil, arg2=nil, arg3=nil)
|
239
|
+
until_sig = Time.now.to_s + ":" + Process.pid.to_s + Random.new.rand(4000000000).to_s + Random.new.rand(4000000000).to_s
|
240
|
+
loop do
|
241
|
+
begin
|
242
|
+
redis.multi do
|
243
|
+
redis.rpush self.agis_mailbox, "m:" + name.to_s
|
244
|
+
redis.rpush self.agis_mailbox, agis_aconv(arg1)
|
245
|
+
redis.rpush self.agis_mailbox, agis_aconv(arg2)
|
246
|
+
redis.rpush self.agis_mailbox, agis_aconv(arg3)
|
247
|
+
redis.rpush self.agis_mailbox, "r:" + until_sig
|
248
|
+
end
|
249
|
+
return _agis_crunch(redis, until_sig)
|
250
|
+
rescue Agis::MessageBoxEmpty
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
# Alias for agis_call
|
256
|
+
def acall(redis, name, arg1=nil, arg2=nil, arg3=nil)
|
257
|
+
agis_call(redis, name, arg1, arg2, arg3)
|
258
|
+
end
|
259
|
+
|
260
|
+
# Method for calling another Agis method, or retrying.
|
261
|
+
# this doesn't touch the message box because it should
|
262
|
+
# only be called inside an Agis method, where the box
|
263
|
+
# is already guaranteed to be locked
|
264
|
+
def agis_recall(mn, arg1=nil, arg2=nil, arg3=nil)
|
265
|
+
meti = @agis_methods[mn.to_sym][1]
|
266
|
+
case meti
|
267
|
+
when Proc
|
268
|
+
met = meti
|
269
|
+
when Symbol
|
270
|
+
met = self.method(meti)
|
271
|
+
when NilClass
|
272
|
+
met = self.method(mn.to_sym) # when proc is Nil, call the class methods all the same
|
273
|
+
end
|
274
|
+
|
275
|
+
case @agis_methods[mn.to_sym][0]
|
276
|
+
when 0
|
277
|
+
return met.call()
|
278
|
+
when 1
|
279
|
+
return met.call(arg1)
|
280
|
+
when 2
|
281
|
+
return met.call(arg1, arg2)
|
282
|
+
when 3
|
283
|
+
return met.call(arg1, arg2, arg3)
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
metadata
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: agis
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.7
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Gert Oja
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-06-07 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: redis
|
15
|
+
version_requirements: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
requirement: !ruby/object:Gem::Requirement
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: '0'
|
25
|
+
prerelease: false
|
26
|
+
type: :development
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: mlanett-redis-lock
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
requirement: !ruby/object:Gem::Requirement
|
35
|
+
requirements:
|
36
|
+
- - ">="
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0'
|
39
|
+
prerelease: false
|
40
|
+
type: :development
|
41
|
+
description: Messagebox Redis Actors for Ruby and ActiveRecord
|
42
|
+
email: gertoja1@gmail.com
|
43
|
+
executables: []
|
44
|
+
extensions: []
|
45
|
+
extra_rdoc_files: []
|
46
|
+
files:
|
47
|
+
- lib/agis.rb
|
48
|
+
homepage: http://rubygems.org/gems/agis
|
49
|
+
licenses:
|
50
|
+
- MIT
|
51
|
+
metadata: {}
|
52
|
+
post_install_message:
|
53
|
+
rdoc_options: []
|
54
|
+
require_paths:
|
55
|
+
- lib
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
requirements: []
|
67
|
+
rubyforge_project:
|
68
|
+
rubygems_version: 2.4.6
|
69
|
+
signing_key:
|
70
|
+
specification_version: 4
|
71
|
+
summary: Messagebox Redis Actors for Ruby
|
72
|
+
test_files: []
|
73
|
+
has_rdoc:
|