fairway 0.2.7 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +13 -5
- data/Gemfile.lock +8 -7
- data/go/channeled_connection_test.go +22 -0
- data/go/config.go +1 -1
- data/go/config_test.go +2 -2
- data/go/connection.go +5 -0
- data/go/connection_test.go +1 -0
- data/go/fairway_ack.go +60 -0
- data/go/fairway_deliver.go +32 -27
- data/go/fairway_destroy.go +11 -6
- data/go/fairway_inflight.go +15 -0
- data/go/fairway_peek.go +1 -3
- data/go/fairway_ping.go +20 -0
- data/go/fairway_priority.go +2 -3
- data/go/fairway_pull.go +67 -61
- data/go/message.go +3 -2
- data/go/queue.go +31 -2
- data/go/queue_test.go +467 -9
- data/go/scripts.go +82 -4
- data/lib/fairway/queue.rb +13 -1
- data/lib/fairway/scripts.rb +20 -0
- data/lib/fairway/version.rb +1 -1
- data/redis/fairway_deliver.lua +32 -26
- data/redis/fairway_priority.lua +1 -1
- data/redis/fairway_pull.lua +66 -59
- data/spec/lib/fairway/channeled_connection_spec.rb +1 -0
- data/spec/lib/fairway/connection_spec.rb +1 -0
- data/spec/lib/fairway/queue_spec.rb +3 -7
- data/spec/lib/fairway/scripts_spec.rb +2 -2
- metadata +16 -13
data/go/queue_test.go
CHANGED
@@ -23,16 +23,128 @@ func QueueSpec(c gospec.Context) {
|
|
23
23
|
conn.Deliver(msg1)
|
24
24
|
conn.Deliver(msg2)
|
25
25
|
|
26
|
-
|
26
|
+
r := config.Pool.Get()
|
27
|
+
defer r.Close()
|
28
|
+
|
29
|
+
count, _ := redis.Int(r.Do("llen", "fairway:myqueue:default"))
|
30
|
+
c.Expect(count, Equals, 2)
|
31
|
+
count, _ = redis.Int(r.Do("scard", "fairway:myqueue:active_facets"))
|
32
|
+
c.Expect(count, Equals, 1)
|
33
|
+
count, _ = redis.Int(r.Do("llen", "fairway:myqueue:facet_queue"))
|
34
|
+
c.Expect(count, Equals, 1)
|
35
|
+
count, _ = redis.Int(r.Do("get", "fairway:myqueue:limit"))
|
36
|
+
c.Expect(count, Equals, 0)
|
37
|
+
count, _ = redis.Int(r.Do("get", "fairway:myqueue:inflight"))
|
38
|
+
c.Expect(count, Equals, 0)
|
39
|
+
count, _ = redis.Int(r.Do("hget", "fairway:myqueue:facet_pool", "default"))
|
40
|
+
c.Expect(count, Equals, 1)
|
41
|
+
|
42
|
+
queueName, message := queue.Pull(-1)
|
43
|
+
|
44
|
+
count, _ = redis.Int(r.Do("llen", "fairway:myqueue:default"))
|
45
|
+
c.Expect(count, Equals, 1)
|
46
|
+
count, _ = redis.Int(r.Do("scard", "fairway:myqueue:active_facets"))
|
47
|
+
c.Expect(count, Equals, 1)
|
48
|
+
count, _ = redis.Int(r.Do("llen", "fairway:myqueue:facet_queue"))
|
49
|
+
c.Expect(count, Equals, 1)
|
50
|
+
count, _ = redis.Int(r.Do("get", "fairway:myqueue:limit"))
|
51
|
+
c.Expect(count, Equals, 0)
|
52
|
+
count, _ = redis.Int(r.Do("get", "fairway:myqueue:inflight"))
|
53
|
+
c.Expect(count, Equals, 0)
|
54
|
+
count, _ = redis.Int(r.Do("hget", "fairway:myqueue:facet_pool", "default"))
|
55
|
+
c.Expect(count, Equals, 1)
|
56
|
+
|
27
57
|
c.Expect(queueName, Equals, "myqueue")
|
28
58
|
c.Expect(message.json(), Equals, msg1.json())
|
29
59
|
|
30
|
-
queueName, message = queue.Pull()
|
60
|
+
queueName, message = queue.Pull(-1)
|
31
61
|
c.Expect(queueName, Equals, "myqueue")
|
32
62
|
c.Expect(message.json(), Equals, msg2.json())
|
33
63
|
})
|
34
64
|
|
35
|
-
c.Specify("
|
65
|
+
c.Specify("places pulled message on inflight sorted set until acknowledged", func() {
|
66
|
+
msg1, _ := NewMsg(map[string]string{"name": "mymessage1"})
|
67
|
+
|
68
|
+
conn.Deliver(msg1)
|
69
|
+
|
70
|
+
c.Expect(len(queue.Inflight()), Equals, 0)
|
71
|
+
|
72
|
+
queueName, message := queue.Pull(100)
|
73
|
+
c.Expect(queueName, Equals, "myqueue")
|
74
|
+
c.Expect(message.json(), Equals, msg1.json())
|
75
|
+
|
76
|
+
c.Expect(len(queue.Inflight()), Equals, 1)
|
77
|
+
c.Expect(queue.Inflight()[0], Equals, msg1.json())
|
78
|
+
|
79
|
+
queue.Ack(msg1)
|
80
|
+
|
81
|
+
c.Expect(len(queue.Inflight()), Equals, 0)
|
82
|
+
})
|
83
|
+
|
84
|
+
c.Specify("pulls from inflight message set if messages are unacknowledged", func() {
|
85
|
+
msg1, _ := NewMsg(map[string]string{"name": "mymessage1"})
|
86
|
+
msg2, _ := NewMsg(map[string]string{"name": "mymessage2"})
|
87
|
+
|
88
|
+
conn.Deliver(msg1)
|
89
|
+
conn.Deliver(msg2)
|
90
|
+
|
91
|
+
queueName, message := queue.Pull(0)
|
92
|
+
c.Expect(queueName, Equals, "myqueue")
|
93
|
+
c.Expect(message.json(), Equals, msg1.json())
|
94
|
+
|
95
|
+
queueName, message = queue.Pull(10)
|
96
|
+
c.Expect(queueName, Equals, "myqueue")
|
97
|
+
c.Expect(message.json(), Equals, msg1.json())
|
98
|
+
|
99
|
+
queueName, message = queue.Pull(10)
|
100
|
+
c.Expect(queueName, Equals, "myqueue")
|
101
|
+
c.Expect(message.json(), Equals, msg2.json())
|
102
|
+
})
|
103
|
+
|
104
|
+
c.Specify("allows puller to ping to keep message inflight", func() {
|
105
|
+
msg1, _ := NewMsg(map[string]string{"name": "mymessage1"})
|
106
|
+
msg2, _ := NewMsg(map[string]string{"name": "mymessage2"})
|
107
|
+
|
108
|
+
conn.Deliver(msg1)
|
109
|
+
conn.Deliver(msg2)
|
110
|
+
|
111
|
+
queueName, message := queue.Pull(0)
|
112
|
+
c.Expect(queueName, Equals, "myqueue")
|
113
|
+
c.Expect(message.json(), Equals, msg1.json())
|
114
|
+
|
115
|
+
// Extends time before message is resent
|
116
|
+
queue.Ping(msg1, 10)
|
117
|
+
|
118
|
+
queueName, message = queue.Pull(10)
|
119
|
+
c.Expect(queueName, Equals, "myqueue")
|
120
|
+
c.Expect(message.json(), Equals, msg2.json())
|
121
|
+
|
122
|
+
// Sets time for message to resend to now
|
123
|
+
queue.Ping(msg1, 0)
|
124
|
+
|
125
|
+
queueName, message = queue.Pull(10)
|
126
|
+
c.Expect(queueName, Equals, "myqueue")
|
127
|
+
c.Expect(message.json(), Equals, msg1.json())
|
128
|
+
})
|
129
|
+
|
130
|
+
c.Specify("set limits messages inflight", func() {
|
131
|
+
limit, err := queue.InflightLimit()
|
132
|
+
|
133
|
+
c.Expect(limit, Equals, 0)
|
134
|
+
c.Expect(err, IsNil)
|
135
|
+
|
136
|
+
queue.SetInflightLimit(1)
|
137
|
+
|
138
|
+
limit, err = queue.InflightLimit()
|
139
|
+
|
140
|
+
c.Expect(limit, Equals, 1)
|
141
|
+
c.Expect(err, IsNil)
|
142
|
+
})
|
143
|
+
|
144
|
+
c.Specify("limits messages inflight", func() {
|
145
|
+
r := config.Pool.Get()
|
146
|
+
defer r.Close()
|
147
|
+
|
36
148
|
config.Facet = func(msg *Msg) string {
|
37
149
|
str, _ := msg.Get("facet").String()
|
38
150
|
return str
|
@@ -46,12 +158,358 @@ func QueueSpec(c gospec.Context) {
|
|
46
158
|
conn.Deliver(msg2)
|
47
159
|
conn.Deliver(msg3)
|
48
160
|
|
49
|
-
|
161
|
+
queue.SetInflightLimit(1)
|
162
|
+
|
163
|
+
_, message := queue.Pull(2)
|
50
164
|
c.Expect(message.json(), Equals, msg1.json())
|
51
|
-
|
165
|
+
|
166
|
+
count, _ := redis.Int(r.Do("get", "fairway:myqueue:1:inflight"))
|
167
|
+
c.Expect(count, Equals, 1)
|
168
|
+
|
169
|
+
_, message = queue.Pull(2)
|
52
170
|
c.Expect(message.json(), Equals, msg3.json())
|
53
|
-
|
171
|
+
|
172
|
+
count, _ = redis.Int(r.Do("get", "fairway:myqueue:1:inflight"))
|
173
|
+
c.Expect(count, Equals, 1)
|
174
|
+
|
175
|
+
count, _ = redis.Int(r.Do("get", "fairway:myqueue:2:inflight"))
|
176
|
+
c.Expect(count, Equals, 1)
|
177
|
+
|
178
|
+
_, message = queue.Pull(2)
|
179
|
+
c.Expect(message, IsNil)
|
180
|
+
_, message = queue.Pull(2)
|
181
|
+
c.Expect(message, IsNil)
|
182
|
+
|
183
|
+
count, _ = redis.Int(r.Do("get", "fairway:myqueue:1:inflight"))
|
184
|
+
c.Expect(count, Equals, 1)
|
185
|
+
|
186
|
+
count, _ = redis.Int(r.Do("get", "fairway:myqueue:2:inflight"))
|
187
|
+
c.Expect(count, Equals, 1)
|
188
|
+
|
189
|
+
queue.Ack(msg1)
|
190
|
+
queue.Ack(msg1)
|
191
|
+
queue.Ack(msg1)
|
192
|
+
queue.Ack(msg1)
|
193
|
+
queue.Ack(msg1)
|
194
|
+
|
195
|
+
count, err := redis.Int(r.Do("get", "fairway:myqueue:1:inflight"))
|
196
|
+
c.Expect(count, Equals, 0)
|
197
|
+
c.Expect(err, IsNil)
|
198
|
+
|
199
|
+
count, _ = redis.Int(r.Do("get", "fairway:myqueue:2:inflight"))
|
200
|
+
c.Expect(count, Equals, 1)
|
201
|
+
|
202
|
+
_, message = queue.Pull(2)
|
54
203
|
c.Expect(message.json(), Equals, msg2.json())
|
204
|
+
|
205
|
+
count, _ = redis.Int(r.Do("get", "fairway:myqueue:1:inflight"))
|
206
|
+
c.Expect(count, Equals, 1)
|
207
|
+
|
208
|
+
count, _ = redis.Int(r.Do("get", "fairway:myqueue:2:inflight"))
|
209
|
+
c.Expect(count, Equals, 1)
|
210
|
+
})
|
211
|
+
|
212
|
+
c.Specify("prevents overlimit messages when all messages are inflight", func() {
|
213
|
+
r := config.Pool.Get()
|
214
|
+
defer r.Close()
|
215
|
+
|
216
|
+
config.Facet = func(msg *Msg) string {
|
217
|
+
str, _ := msg.Get("facet").String()
|
218
|
+
return str
|
219
|
+
}
|
220
|
+
|
221
|
+
msg1, _ := NewMsg(map[string]string{"facet": "1", "name": "mymessage1"})
|
222
|
+
msg2, _ := NewMsg(map[string]string{"facet": "1", "name": "mymessage2"})
|
223
|
+
msg3, _ := NewMsg(map[string]string{"facet": "1", "name": "mymessage3"})
|
224
|
+
|
225
|
+
queue.SetInflightLimit(1)
|
226
|
+
|
227
|
+
active, _ := redis.Strings(r.Do("smembers", "fairway:myqueue:active_facets"))
|
228
|
+
c.Expect(len(active), Equals, 0)
|
229
|
+
fqueue, _ := redis.Int(r.Do("llen", "fairway:myqueue:facet_queue"))
|
230
|
+
c.Expect(fqueue, Equals, 0)
|
231
|
+
|
232
|
+
conn.Deliver(msg1)
|
233
|
+
|
234
|
+
active, _ = redis.Strings(r.Do("smembers", "fairway:myqueue:active_facets"))
|
235
|
+
c.Expect(len(active), Equals, 1)
|
236
|
+
c.Expect(active[0], Equals, "1")
|
237
|
+
fqueue, _ = redis.Int(r.Do("llen", "fairway:myqueue:facet_queue"))
|
238
|
+
c.Expect(fqueue, Equals, 1)
|
239
|
+
|
240
|
+
_, message := queue.Pull(2)
|
241
|
+
c.Expect(message.json(), Equals, msg1.json())
|
242
|
+
|
243
|
+
active, _ = redis.Strings(r.Do("smembers", "fairway:myqueue:active_facets"))
|
244
|
+
c.Expect(len(active), Equals, 1)
|
245
|
+
c.Expect(active[0], Equals, "1")
|
246
|
+
fqueue, _ = redis.Int(r.Do("llen", "fairway:myqueue:facet_queue"))
|
247
|
+
c.Expect(fqueue, Equals, 0)
|
248
|
+
|
249
|
+
conn.Deliver(msg2)
|
250
|
+
|
251
|
+
_, message = queue.Pull(2)
|
252
|
+
c.Expect(message, IsNil)
|
253
|
+
|
254
|
+
active, _ = redis.Strings(r.Do("smembers", "fairway:myqueue:active_facets"))
|
255
|
+
c.Expect(len(active), Equals, 1)
|
256
|
+
c.Expect(active[0], Equals, "1")
|
257
|
+
fqueue, _ = redis.Int(r.Do("llen", "fairway:myqueue:facet_queue"))
|
258
|
+
c.Expect(fqueue, Equals, 0)
|
259
|
+
|
260
|
+
queue.Ack(msg1)
|
261
|
+
|
262
|
+
active, _ = redis.Strings(r.Do("smembers", "fairway:myqueue:active_facets"))
|
263
|
+
c.Expect(len(active), Equals, 1)
|
264
|
+
c.Expect(active[0], Equals, "1")
|
265
|
+
fqueue, _ = redis.Int(r.Do("llen", "fairway:myqueue:facet_queue"))
|
266
|
+
c.Expect(fqueue, Equals, 1)
|
267
|
+
|
268
|
+
_, message = queue.Pull(2)
|
269
|
+
c.Expect(message.json(), Equals, msg2.json())
|
270
|
+
|
271
|
+
active, _ = redis.Strings(r.Do("smembers", "fairway:myqueue:active_facets"))
|
272
|
+
c.Expect(len(active), Equals, 1)
|
273
|
+
c.Expect(active[0], Equals, "1")
|
274
|
+
fqueue, _ = redis.Int(r.Do("llen", "fairway:myqueue:facet_queue"))
|
275
|
+
c.Expect(fqueue, Equals, 0)
|
276
|
+
|
277
|
+
conn.Deliver(msg3)
|
278
|
+
|
279
|
+
active, _ = redis.Strings(r.Do("smembers", "fairway:myqueue:active_facets"))
|
280
|
+
c.Expect(len(active), Equals, 1)
|
281
|
+
c.Expect(active[0], Equals, "1")
|
282
|
+
fqueue, _ = redis.Int(r.Do("llen", "fairway:myqueue:facet_queue"))
|
283
|
+
c.Expect(fqueue, Equals, 0)
|
284
|
+
|
285
|
+
_, message = queue.Pull(2)
|
286
|
+
c.Expect(message, IsNil)
|
287
|
+
|
288
|
+
queue.Ack(msg2)
|
289
|
+
|
290
|
+
active, _ = redis.Strings(r.Do("smembers", "fairway:myqueue:active_facets"))
|
291
|
+
c.Expect(len(active), Equals, 1)
|
292
|
+
c.Expect(active[0], Equals, "1")
|
293
|
+
fqueue, _ = redis.Int(r.Do("llen", "fairway:myqueue:facet_queue"))
|
294
|
+
c.Expect(fqueue, Equals, 1)
|
295
|
+
|
296
|
+
_, message = queue.Pull(2)
|
297
|
+
c.Expect(message.json(), Equals, msg3.json())
|
298
|
+
|
299
|
+
active, _ = redis.Strings(r.Do("smembers", "fairway:myqueue:active_facets"))
|
300
|
+
c.Expect(len(active), Equals, 1)
|
301
|
+
c.Expect(active[0], Equals, "1")
|
302
|
+
fqueue, _ = redis.Int(r.Do("llen", "fairway:myqueue:facet_queue"))
|
303
|
+
c.Expect(fqueue, Equals, 0)
|
304
|
+
|
305
|
+
_, message = queue.Pull(2)
|
306
|
+
c.Expect(message, IsNil)
|
307
|
+
|
308
|
+
queue.Ack(msg3)
|
309
|
+
|
310
|
+
active, _ = redis.Strings(r.Do("smembers", "fairway:myqueue:active_facets"))
|
311
|
+
c.Expect(len(active), Equals, 0)
|
312
|
+
fqueue, _ = redis.Int(r.Do("llen", "fairway:myqueue:facet_queue"))
|
313
|
+
c.Expect(fqueue, Equals, 0)
|
314
|
+
|
315
|
+
msg4, _ := NewMsg(map[string]string{"facet": "1", "name": "mymessage4"})
|
316
|
+
|
317
|
+
conn.Deliver(msg4)
|
318
|
+
|
319
|
+
active, _ = redis.Strings(r.Do("smembers", "fairway:myqueue:active_facets"))
|
320
|
+
c.Expect(len(active), Equals, 1)
|
321
|
+
fqueue, _ = redis.Int(r.Do("llen", "fairway:myqueue:facet_queue"))
|
322
|
+
c.Expect(fqueue, Equals, 1)
|
323
|
+
|
324
|
+
_, message = queue.Pull(2)
|
325
|
+
c.Expect(message.json(), Equals, msg4.json())
|
326
|
+
|
327
|
+
active, _ = redis.Strings(r.Do("smembers", "fairway:myqueue:active_facets"))
|
328
|
+
c.Expect(len(active), Equals, 1)
|
329
|
+
fqueue, _ = redis.Int(r.Do("llen", "fairway:myqueue:facet_queue"))
|
330
|
+
c.Expect(fqueue, Equals, 0)
|
331
|
+
|
332
|
+
queue.Ack(msg4)
|
333
|
+
|
334
|
+
active, _ = redis.Strings(r.Do("smembers", "fairway:myqueue:active_facets"))
|
335
|
+
c.Expect(len(active), Equals, 0)
|
336
|
+
fqueue, _ = redis.Int(r.Do("llen", "fairway:myqueue:facet_queue"))
|
337
|
+
c.Expect(fqueue, Equals, 0)
|
338
|
+
|
339
|
+
_, message = queue.Pull(2)
|
340
|
+
c.Expect(message, IsNil)
|
341
|
+
|
342
|
+
active, _ = redis.Strings(r.Do("smembers", "fairway:myqueue:active_facets"))
|
343
|
+
c.Expect(len(active), Equals, 0)
|
344
|
+
fqueue, _ = redis.Int(r.Do("llen", "fairway:myqueue:facet_queue"))
|
345
|
+
c.Expect(fqueue, Equals, 0)
|
346
|
+
})
|
347
|
+
|
348
|
+
c.Specify("if inflight limit is 0, no limit", func() {
|
349
|
+
r := config.Pool.Get()
|
350
|
+
defer r.Close()
|
351
|
+
|
352
|
+
config.Facet = func(msg *Msg) string {
|
353
|
+
str, _ := msg.Get("facet").String()
|
354
|
+
return str
|
355
|
+
}
|
356
|
+
|
357
|
+
msg1, _ := NewMsg(map[string]string{"facet": "1", "name": "mymessage1"})
|
358
|
+
msg2, _ := NewMsg(map[string]string{"facet": "1", "name": "mymessage2"})
|
359
|
+
msg3, _ := NewMsg(map[string]string{"facet": "2", "name": "mymessage3"})
|
360
|
+
|
361
|
+
queue.SetInflightLimit(0)
|
362
|
+
|
363
|
+
conn.Deliver(msg1)
|
364
|
+
conn.Deliver(msg2)
|
365
|
+
conn.Deliver(msg3)
|
366
|
+
|
367
|
+
active, _ := redis.Strings(r.Do("smembers", "fairway:myqueue:active_facets"))
|
368
|
+
c.Expect(len(active), Equals, 2)
|
369
|
+
fqueue, _ := redis.Int(r.Do("llen", "fairway:myqueue:facet_queue"))
|
370
|
+
c.Expect(fqueue, Equals, 2)
|
371
|
+
|
372
|
+
_, message := queue.Pull(2)
|
373
|
+
c.Expect(message.json(), Equals, msg1.json())
|
374
|
+
|
375
|
+
_, message = queue.Pull(2)
|
376
|
+
c.Expect(message.json(), Equals, msg3.json())
|
377
|
+
|
378
|
+
active, _ = redis.Strings(r.Do("smembers", "fairway:myqueue:active_facets"))
|
379
|
+
c.Expect(len(active), Equals, 2)
|
380
|
+
fqueue, _ = redis.Int(r.Do("llen", "fairway:myqueue:facet_queue"))
|
381
|
+
c.Expect(fqueue, Equals, 1)
|
382
|
+
|
383
|
+
_, message = queue.Pull(2)
|
384
|
+
c.Expect(message.json(), Equals, msg2.json())
|
385
|
+
|
386
|
+
active, _ = redis.Strings(r.Do("smembers", "fairway:myqueue:active_facets"))
|
387
|
+
c.Expect(len(active), Equals, 2)
|
388
|
+
fqueue, _ = redis.Int(r.Do("llen", "fairway:myqueue:facet_queue"))
|
389
|
+
c.Expect(fqueue, Equals, 0)
|
390
|
+
|
391
|
+
msg4, _ := NewMsg(map[string]string{"facet": "2", "name": "mymessage4"})
|
392
|
+
|
393
|
+
conn.Deliver(msg4)
|
394
|
+
|
395
|
+
active, _ = redis.Strings(r.Do("smembers", "fairway:myqueue:active_facets"))
|
396
|
+
c.Expect(len(active), Equals, 2)
|
397
|
+
fqueue, _ = redis.Int(r.Do("llen", "fairway:myqueue:facet_queue"))
|
398
|
+
c.Expect(fqueue, Equals, 1)
|
399
|
+
|
400
|
+
queue.Ack(msg1)
|
401
|
+
queue.Ack(msg2)
|
402
|
+
|
403
|
+
active, _ = redis.Strings(r.Do("smembers", "fairway:myqueue:active_facets"))
|
404
|
+
c.Expect(len(active), Equals, 1)
|
405
|
+
fqueue, _ = redis.Int(r.Do("llen", "fairway:myqueue:facet_queue"))
|
406
|
+
c.Expect(fqueue, Equals, 1)
|
407
|
+
|
408
|
+
_, message = queue.Pull(2)
|
409
|
+
c.Expect(message.json(), Equals, msg4.json())
|
410
|
+
|
411
|
+
active, _ = redis.Strings(r.Do("smembers", "fairway:myqueue:active_facets"))
|
412
|
+
c.Expect(len(active), Equals, 1)
|
413
|
+
fqueue, _ = redis.Int(r.Do("llen", "fairway:myqueue:facet_queue"))
|
414
|
+
c.Expect(fqueue, Equals, 0)
|
415
|
+
|
416
|
+
_, message = queue.Pull(2)
|
417
|
+
c.Expect(message, IsNil)
|
418
|
+
|
419
|
+
queue.Ack(msg3)
|
420
|
+
|
421
|
+
active, _ = redis.Strings(r.Do("smembers", "fairway:myqueue:active_facets"))
|
422
|
+
c.Expect(len(active), Equals, 1)
|
423
|
+
fqueue, _ = redis.Int(r.Do("llen", "fairway:myqueue:facet_queue"))
|
424
|
+
c.Expect(fqueue, Equals, 0)
|
425
|
+
|
426
|
+
queue.Ack(msg4)
|
427
|
+
|
428
|
+
active, _ = redis.Strings(r.Do("smembers", "fairway:myqueue:active_facets"))
|
429
|
+
c.Expect(len(active), Equals, 0)
|
430
|
+
fqueue, _ = redis.Int(r.Do("llen", "fairway:myqueue:facet_queue"))
|
431
|
+
c.Expect(fqueue, Equals, 0)
|
432
|
+
|
433
|
+
})
|
434
|
+
|
435
|
+
c.Specify("doesn't place pulled message on inflight sorted set if inflight is disabled", func() {
|
436
|
+
msg1, _ := NewMsg(map[string]string{"name": "mymessage1"})
|
437
|
+
|
438
|
+
conn.Deliver(msg1)
|
439
|
+
|
440
|
+
c.Expect(len(queue.Inflight()), Equals, 0)
|
441
|
+
|
442
|
+
queueName, message := queue.Pull(-1)
|
443
|
+
c.Expect(queueName, Equals, "myqueue")
|
444
|
+
c.Expect(message.json(), Equals, msg1.json())
|
445
|
+
|
446
|
+
c.Expect(len(queue.Inflight()), Equals, 0)
|
447
|
+
})
|
448
|
+
|
449
|
+
c.Specify("doesn't pull from inflight message set if inflight is disabled", func() {
|
450
|
+
msg1, _ := NewMsg(map[string]string{"name": "mymessage1"})
|
451
|
+
msg2, _ := NewMsg(map[string]string{"name": "mymessage2"})
|
452
|
+
|
453
|
+
conn.Deliver(msg1)
|
454
|
+
conn.Deliver(msg2)
|
455
|
+
|
456
|
+
queueName, message := queue.Pull(-1)
|
457
|
+
c.Expect(queueName, Equals, "myqueue")
|
458
|
+
c.Expect(message.json(), Equals, msg1.json())
|
459
|
+
|
460
|
+
queueName, message = queue.Pull(-1)
|
461
|
+
c.Expect(queueName, Equals, "myqueue")
|
462
|
+
c.Expect(message.json(), Equals, msg2.json())
|
463
|
+
})
|
464
|
+
|
465
|
+
c.Specify("pulls from facets of the queue in round-robin", func() {
|
466
|
+
r := config.Pool.Get()
|
467
|
+
defer r.Close()
|
468
|
+
|
469
|
+
config.Facet = func(msg *Msg) string {
|
470
|
+
str, _ := msg.Get("facet").String()
|
471
|
+
return str
|
472
|
+
}
|
473
|
+
|
474
|
+
msg1, _ := NewMsg(map[string]string{"facet": "1", "name": "my message1"})
|
475
|
+
msg2, _ := NewMsg(map[string]string{"facet": "1", "name": "my message2"})
|
476
|
+
msg3, _ := NewMsg(map[string]string{"facet": "2", "name": "my message3"})
|
477
|
+
|
478
|
+
active, _ := redis.Strings(r.Do("smembers", "fairway:myqueue:active_facets"))
|
479
|
+
c.Expect(len(active), Equals, 0)
|
480
|
+
|
481
|
+
conn.Deliver(msg1)
|
482
|
+
conn.Deliver(msg2)
|
483
|
+
|
484
|
+
active, _ = redis.Strings(r.Do("smembers", "fairway:myqueue:active_facets"))
|
485
|
+
c.Expect(len(active), Equals, 1)
|
486
|
+
c.Expect(active[0], Equals, "1")
|
487
|
+
|
488
|
+
conn.Deliver(msg3)
|
489
|
+
|
490
|
+
active, _ = redis.Strings(r.Do("smembers", "fairway:myqueue:active_facets"))
|
491
|
+
c.Expect(len(active), Equals, 2)
|
492
|
+
c.Expect(active[0], Equals, "1")
|
493
|
+
c.Expect(active[1], Equals, "2")
|
494
|
+
|
495
|
+
_, message := queue.Pull(-1)
|
496
|
+
c.Expect(message.json(), Equals, msg1.json())
|
497
|
+
|
498
|
+
_, message = queue.Pull(-1)
|
499
|
+
c.Expect(message.json(), Equals, msg3.json())
|
500
|
+
|
501
|
+
active, _ = redis.Strings(r.Do("smembers", "fairway:myqueue:active_facets"))
|
502
|
+
c.Expect(len(active), Equals, 1)
|
503
|
+
c.Expect(active[0], Equals, "1")
|
504
|
+
|
505
|
+
_, message = queue.Pull(-1)
|
506
|
+
c.Expect(message.json(), Equals, msg2.json())
|
507
|
+
|
508
|
+
active, _ = redis.Strings(r.Do("smembers", "fairway:myqueue:active_facets"))
|
509
|
+
c.Expect(len(active), Equals, 0)
|
510
|
+
|
511
|
+
_, message = queue.Pull(2)
|
512
|
+
c.Expect(message, IsNil)
|
55
513
|
})
|
56
514
|
|
57
515
|
c.Specify("removes facet from active list if it becomes empty", func() {
|
@@ -64,7 +522,7 @@ func QueueSpec(c gospec.Context) {
|
|
64
522
|
count, _ := redis.Int(r.Do("scard", "fairway:myqueue:active_facets"))
|
65
523
|
c.Expect(count, Equals, 1)
|
66
524
|
|
67
|
-
queue.Pull()
|
525
|
+
queue.Pull(-1)
|
68
526
|
|
69
527
|
count, _ = redis.Int(r.Do("scard", "fairway:myqueue:active_facets"))
|
70
528
|
c.Expect(count, Equals, 0)
|
@@ -74,9 +532,9 @@ func QueueSpec(c gospec.Context) {
|
|
74
532
|
msg, _ := NewMsg(map[string]string{})
|
75
533
|
conn.Deliver(msg)
|
76
534
|
|
77
|
-
queueName, message := queue.Pull()
|
535
|
+
queueName, message := queue.Pull(-1)
|
78
536
|
c.Expect(queueName, Equals, "myqueue")
|
79
|
-
queueName, message = queue.Pull()
|
537
|
+
queueName, message = queue.Pull(-1)
|
80
538
|
c.Expect(queueName, Equals, "")
|
81
539
|
c.Expect(message, IsNil)
|
82
540
|
})
|
data/go/scripts.go
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
package fairway
|
2
2
|
|
3
3
|
import (
|
4
|
-
"fmt"
|
5
4
|
"github.com/customerio/redigo/redis"
|
5
|
+
|
6
|
+
"fmt"
|
7
|
+
"time"
|
6
8
|
)
|
7
9
|
|
8
10
|
type scripts struct {
|
@@ -56,13 +58,30 @@ func (s *scripts) deliver(channel, facet string, msg *Msg) error {
|
|
56
58
|
return err
|
57
59
|
}
|
58
60
|
|
59
|
-
func (s *scripts)
|
61
|
+
func (s *scripts) deliverBytes(channel, facet string, msg []byte) error {
|
60
62
|
conn := s.config.Pool.Get()
|
61
63
|
defer conn.Close()
|
62
64
|
|
63
|
-
script := s.findScript(
|
65
|
+
script := s.findScript(FairwayDeliver, 1)
|
66
|
+
|
67
|
+
_, err := script.Do(conn, s.namespace(), channel, facet, string(msg))
|
64
68
|
|
65
|
-
|
69
|
+
return err
|
70
|
+
}
|
71
|
+
|
72
|
+
func (s *scripts) length(queue string) (int, error) {
|
73
|
+
conn := s.config.Pool.Get()
|
74
|
+
defer conn.Close()
|
75
|
+
return redis.Int(conn.Do("get", s.namespace()+queue+":length"))
|
76
|
+
}
|
77
|
+
|
78
|
+
func (s *scripts) pull(queueName string, wait int) (string, *Msg) {
|
79
|
+
conn := s.config.Pool.Get()
|
80
|
+
defer conn.Close()
|
81
|
+
|
82
|
+
script := s.findScript(FairwayPull, 3)
|
83
|
+
|
84
|
+
result, err := redis.Strings(script.Do(conn, s.namespace(), int(time.Now().Unix()), wait, queueName))
|
66
85
|
|
67
86
|
if err != nil {
|
68
87
|
return "", nil
|
@@ -74,6 +93,65 @@ func (s *scripts) pull(queueName string) (string, *Msg) {
|
|
74
93
|
return queue, message
|
75
94
|
}
|
76
95
|
|
96
|
+
func (s *scripts) inflight(queueName string) []string {
|
97
|
+
conn := s.config.Pool.Get()
|
98
|
+
defer conn.Close()
|
99
|
+
|
100
|
+
script := s.findScript(FairwayInflight, 1)
|
101
|
+
|
102
|
+
result, err := redis.Strings(script.Do(conn, s.namespace(), queueName))
|
103
|
+
|
104
|
+
if err != nil {
|
105
|
+
return []string{}
|
106
|
+
}
|
107
|
+
|
108
|
+
return result
|
109
|
+
}
|
110
|
+
|
111
|
+
func (s *scripts) inflightLimit(queue string) (limit int, err error) {
|
112
|
+
conn := s.config.Pool.Get()
|
113
|
+
defer conn.Close()
|
114
|
+
|
115
|
+
limit, err = redis.Int(conn.Do("get", s.namespace()+queue+":limit"))
|
116
|
+
|
117
|
+
if err != nil && err.Error() == "redigo: nil returned" {
|
118
|
+
return 0, nil
|
119
|
+
}
|
120
|
+
|
121
|
+
return
|
122
|
+
}
|
123
|
+
|
124
|
+
func (s *scripts) setInflightLimit(queue string, limit int) (err error) {
|
125
|
+
conn := s.config.Pool.Get()
|
126
|
+
defer conn.Close()
|
127
|
+
|
128
|
+
_, err = conn.Do("set", s.namespace()+queue+":limit", limit)
|
129
|
+
|
130
|
+
return
|
131
|
+
}
|
132
|
+
|
133
|
+
func (s *scripts) ping(queueName string, message *Msg, wait int) error {
|
134
|
+
conn := s.config.Pool.Get()
|
135
|
+
defer conn.Close()
|
136
|
+
|
137
|
+
script := s.findScript(FairwayPing, 3)
|
138
|
+
|
139
|
+
_, err := redis.Strings(script.Do(conn, s.namespace(), int(time.Now().Unix()), wait, queueName, message.Original))
|
140
|
+
|
141
|
+
return err
|
142
|
+
}
|
143
|
+
|
144
|
+
func (s *scripts) ack(queueName string, facet string, message *Msg) error {
|
145
|
+
conn := s.config.Pool.Get()
|
146
|
+
defer conn.Close()
|
147
|
+
|
148
|
+
script := s.findScript(FairwayAck, 1)
|
149
|
+
|
150
|
+
_, err := redis.Strings(script.Do(conn, s.namespace(), queueName, facet, message.Original))
|
151
|
+
|
152
|
+
return err
|
153
|
+
}
|
154
|
+
|
77
155
|
func (s *scripts) findScript(script func() string, keyCount int) *redis.Script {
|
78
156
|
content := script()
|
79
157
|
|
data/lib/fairway/queue.rb
CHANGED
@@ -29,12 +29,24 @@ module Fairway
|
|
29
29
|
end.sum
|
30
30
|
end
|
31
31
|
|
32
|
+
def inflight_limit=(limit)
|
33
|
+
redis.with_each do |conn|
|
34
|
+
unique_queues.each do |queue|
|
35
|
+
if limit < 1
|
36
|
+
conn.del("#{queue}:limit")
|
37
|
+
else
|
38
|
+
conn.set("#{queue}:limit", limit)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
32
44
|
def peek
|
33
45
|
scripts.fairway_peek(@queue_names.shuffle.uniq)
|
34
46
|
end
|
35
47
|
|
36
48
|
def pull
|
37
|
-
scripts.fairway_pull(@queue_names.shuffle.uniq)
|
49
|
+
scripts.fairway_pull(Time.now.to_i, -1, @queue_names.shuffle.uniq)
|
38
50
|
end
|
39
51
|
|
40
52
|
def ==(other)
|
data/lib/fairway/scripts.rb
CHANGED
@@ -32,6 +32,26 @@ module Fairway
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
+
def fairway_pull(timestamp, wait, queue_name)
|
36
|
+
loaded = false
|
37
|
+
|
38
|
+
first_pool do |conn|
|
39
|
+
conn.evalsha(script_sha(:fairway_pull), [namespace, timestamp, wait], [queue_name])
|
40
|
+
end
|
41
|
+
|
42
|
+
rescue Redis::CommandError => ex
|
43
|
+
if ex.message.include?("NOSCRIPT") && !loaded
|
44
|
+
redis.with_each do |conn|
|
45
|
+
conn.script(:load, script_source(:fairway_pull))
|
46
|
+
end
|
47
|
+
|
48
|
+
loaded = true
|
49
|
+
retry
|
50
|
+
else
|
51
|
+
raise
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
35
55
|
def method_missing(method_name, *args)
|
36
56
|
loaded = false
|
37
57
|
|
data/lib/fairway/version.rb
CHANGED