queue_classic 2.0.0 → 2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/queue_classic.rb +0 -3
- data/lib/queue_classic/conn.rb +2 -0
- data/lib/queue_classic/okjson.rb +57 -67
- data/lib/queue_classic/queue.rb +2 -2
- data/readme.md +8 -18
- data/test/queue_test.rb +17 -0
- metadata +8 -7
data/lib/queue_classic.rb
CHANGED
@@ -12,9 +12,6 @@ require "queue_classic/worker"
|
|
12
12
|
require "queue_classic/setup"
|
13
13
|
|
14
14
|
module QC
|
15
|
-
# ENV["LOG_LEVEL"] is used in Scrolls
|
16
|
-
Scrolls::Log.start
|
17
|
-
|
18
15
|
Root = File.expand_path("..", File.dirname(__FILE__))
|
19
16
|
SqlFunctions = File.join(QC::Root, "/sql/ddl.sql")
|
20
17
|
DropSqlFunctions = File.join(QC::Root, "/sql/drop_ddl.sql")
|
data/lib/queue_classic/conn.rb
CHANGED
@@ -12,6 +12,7 @@ module QC
|
|
12
12
|
result.length > 1 ? result : result.pop
|
13
13
|
rescue PGError => e
|
14
14
|
log(:error => e.inspect)
|
15
|
+
disconnect
|
15
16
|
raise
|
16
17
|
end
|
17
18
|
end
|
@@ -64,6 +65,7 @@ module QC
|
|
64
65
|
|
65
66
|
def disconnect
|
66
67
|
connection.finish
|
68
|
+
ensure
|
67
69
|
@connection = nil
|
68
70
|
end
|
69
71
|
|
data/lib/queue_classic/okjson.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
module QC
|
2
1
|
# encoding: UTF-8
|
3
2
|
#
|
4
3
|
# Copyright 2011, 2012 Keith Rarick
|
@@ -28,6 +27,7 @@ require 'stringio'
|
|
28
27
|
# Some parts adapted from
|
29
28
|
# http://golang.org/src/pkg/json/decode.go and
|
30
29
|
# http://golang.org/src/pkg/utf8/utf8.go
|
30
|
+
module QC
|
31
31
|
module OkJson
|
32
32
|
extend self
|
33
33
|
|
@@ -220,9 +220,9 @@ module OkJson
|
|
220
220
|
end
|
221
221
|
|
222
222
|
|
223
|
-
def nulltok(s); s[0,4] == 'null'
|
224
|
-
def truetok(s); s[0,4] == 'true'
|
225
|
-
def falsetok(s); s[0,5] == 'false'
|
223
|
+
def nulltok(s); s[0,4] == 'null' ? [:val, 'null', nil] : [] end
|
224
|
+
def truetok(s); s[0,4] == 'true' ? [:val, 'true', true] : [] end
|
225
|
+
def falsetok(s); s[0,5] == 'false' ? [:val, 'false', false] : [] end
|
226
226
|
|
227
227
|
|
228
228
|
def numtok(s)
|
@@ -235,6 +235,8 @@ module OkJson
|
|
235
235
|
else
|
236
236
|
[:val, m[0], Integer(m[0])]
|
237
237
|
end
|
238
|
+
else
|
239
|
+
[]
|
238
240
|
end
|
239
241
|
end
|
240
242
|
|
@@ -375,15 +377,6 @@ module OkJson
|
|
375
377
|
end
|
376
378
|
|
377
379
|
|
378
|
-
def unsubst(u)
|
379
|
-
if u < Usurrself || u > Umax || surrogate?(u)
|
380
|
-
return Ucharerr, Ucharerr
|
381
|
-
end
|
382
|
-
u -= Usurrself
|
383
|
-
[Usurr1 + ((u>>10)&0x3ff), Usurr2 + (u&0x3ff)]
|
384
|
-
end
|
385
|
-
|
386
|
-
|
387
380
|
def surrogate?(u)
|
388
381
|
Usurr1 <= u && u < Usurr3
|
389
382
|
end
|
@@ -473,15 +466,18 @@ module OkJson
|
|
473
466
|
else
|
474
467
|
c = s[r]
|
475
468
|
case true
|
469
|
+
when rubydoesenc
|
470
|
+
begin
|
471
|
+
c.ord # will raise an error if c is invalid UTF-8
|
472
|
+
t.write(c)
|
473
|
+
rescue
|
474
|
+
t.write(Ustrerr)
|
475
|
+
end
|
476
476
|
when Spc <= c && c <= ?~
|
477
477
|
t.putc(c)
|
478
|
-
when rubydoesenc
|
479
|
-
u = c.ord
|
480
|
-
surrenc(t, u)
|
481
478
|
else
|
482
|
-
|
483
|
-
r +=
|
484
|
-
surrenc(t, u)
|
479
|
+
n = ucharcopy(t, s, r) # ensure valid UTF-8 output
|
480
|
+
r += n - 1 # r is incremented below
|
485
481
|
end
|
486
482
|
end
|
487
483
|
r += 1
|
@@ -491,28 +487,6 @@ module OkJson
|
|
491
487
|
end
|
492
488
|
|
493
489
|
|
494
|
-
def surrenc(t, u)
|
495
|
-
if u < 0x10000
|
496
|
-
t.print('\\u')
|
497
|
-
hexenc4(t, u)
|
498
|
-
else
|
499
|
-
u1, u2 = unsubst(u)
|
500
|
-
t.print('\\u')
|
501
|
-
hexenc4(t, u1)
|
502
|
-
t.print('\\u')
|
503
|
-
hexenc4(t, u2)
|
504
|
-
end
|
505
|
-
end
|
506
|
-
|
507
|
-
|
508
|
-
def hexenc4(t, u)
|
509
|
-
t.putc(Hex[(u>>12)&0xf])
|
510
|
-
t.putc(Hex[(u>>8)&0xf])
|
511
|
-
t.putc(Hex[(u>>4)&0xf])
|
512
|
-
t.putc(Hex[u&0xf])
|
513
|
-
end
|
514
|
-
|
515
|
-
|
516
490
|
def numenc(x)
|
517
491
|
if ((x.nan? || x.infinite?) rescue false)
|
518
492
|
raise Error, "Numeric cannot be represented: #{x}"
|
@@ -521,60 +495,77 @@ module OkJson
|
|
521
495
|
end
|
522
496
|
|
523
497
|
|
524
|
-
#
|
525
|
-
#
|
526
|
-
#
|
527
|
-
|
498
|
+
# Copies the valid UTF-8 bytes of a single character
|
499
|
+
# from string s at position i to I/O object t, and
|
500
|
+
# returns the number of bytes copied.
|
501
|
+
# If no valid UTF-8 char exists at position i,
|
502
|
+
# ucharcopy writes Ustrerr and returns 1.
|
503
|
+
def ucharcopy(t, s, i)
|
528
504
|
n = s.length - i
|
529
|
-
|
505
|
+
raise Utf8Error if n < 1
|
530
506
|
|
531
507
|
c0 = s[i].ord
|
532
508
|
|
533
509
|
# 1-byte, 7-bit sequence?
|
534
510
|
if c0 < Utagx
|
535
|
-
|
511
|
+
t.putc(c0)
|
512
|
+
return 1
|
536
513
|
end
|
537
514
|
|
538
|
-
# unexpected continuation byte?
|
539
|
-
return [Ucharerr, 1] if c0 < Utag2
|
515
|
+
raise Utf8Error if c0 < Utag2 # unexpected continuation byte?
|
540
516
|
|
541
|
-
# need continuation byte
|
542
|
-
return [Ucharerr, 1] if n < 2
|
517
|
+
raise Utf8Error if n < 2 # need continuation byte
|
543
518
|
c1 = s[i+1].ord
|
544
|
-
|
519
|
+
raise Utf8Error if c1 < Utagx || Utag2 <= c1
|
545
520
|
|
546
521
|
# 2-byte, 11-bit sequence?
|
547
522
|
if c0 < Utag3
|
548
|
-
|
549
|
-
|
550
|
-
|
523
|
+
raise Utf8Error if ((c0&Umask2)<<6 | (c1&Umaskx)) <= Uchar1max
|
524
|
+
t.putc(c0)
|
525
|
+
t.putc(c1)
|
526
|
+
return 2
|
551
527
|
end
|
552
528
|
|
553
529
|
# need second continuation byte
|
554
|
-
|
530
|
+
raise Utf8Error if n < 3
|
531
|
+
|
555
532
|
c2 = s[i+2].ord
|
556
|
-
|
533
|
+
raise Utf8Error if c2 < Utagx || Utag2 <= c2
|
557
534
|
|
558
535
|
# 3-byte, 16-bit sequence?
|
559
536
|
if c0 < Utag4
|
560
537
|
u = (c0&Umask3)<<12 | (c1&Umaskx)<<6 | (c2&Umaskx)
|
561
|
-
|
562
|
-
|
538
|
+
raise Utf8Error if u <= Uchar2max
|
539
|
+
t.putc(c0)
|
540
|
+
t.putc(c1)
|
541
|
+
t.putc(c2)
|
542
|
+
return 3
|
563
543
|
end
|
564
544
|
|
565
545
|
# need third continuation byte
|
566
|
-
|
546
|
+
raise Utf8Error if n < 4
|
567
547
|
c3 = s[i+3].ord
|
568
|
-
|
548
|
+
raise Utf8Error if c3 < Utagx || Utag2 <= c3
|
569
549
|
|
570
550
|
# 4-byte, 21-bit sequence?
|
571
551
|
if c0 < Utag5
|
572
552
|
u = (c0&Umask4)<<18 | (c1&Umaskx)<<12 | (c2&Umaskx)<<6 | (c3&Umaskx)
|
573
|
-
|
574
|
-
|
575
|
-
|
553
|
+
raise Utf8Error if u <= Uchar3max
|
554
|
+
t.putc(c0)
|
555
|
+
t.putc(c1)
|
556
|
+
t.putc(c2)
|
557
|
+
t.putc(c3)
|
558
|
+
return 4
|
559
|
+
end
|
560
|
+
|
561
|
+
raise Utf8Error
|
562
|
+
rescue Utf8Error
|
563
|
+
t.write(Ustrerr)
|
564
|
+
return 1
|
565
|
+
end
|
566
|
+
|
576
567
|
|
577
|
-
|
568
|
+
class Utf8Error < ::StandardError
|
578
569
|
end
|
579
570
|
|
580
571
|
|
@@ -595,14 +586,13 @@ module OkJson
|
|
595
586
|
Uchar2max = (1<<11) - 1
|
596
587
|
Uchar3max = (1<<16) - 1
|
597
588
|
Ucharerr = 0xFFFD # unicode "replacement char"
|
589
|
+
Ustrerr = "\xef\xbf\xbd" # unicode "replacement char"
|
598
590
|
Usurrself = 0x10000
|
599
591
|
Usurr1 = 0xd800
|
600
592
|
Usurr2 = 0xdc00
|
601
593
|
Usurr3 = 0xe000
|
602
|
-
Umax = 0x10ffff
|
603
594
|
|
604
595
|
Spc = ' '[0]
|
605
596
|
Unesc = {?b=>?\b, ?f=>?\f, ?n=>?\n, ?r=>?\r, ?t=>?\t}
|
606
|
-
Hex = '0123456789abcdef'
|
607
597
|
end
|
608
598
|
end
|
data/lib/queue_classic/queue.rb
CHANGED
data/readme.md
CHANGED
@@ -135,7 +135,7 @@ end
|
|
135
135
|
## Configure
|
136
136
|
|
137
137
|
All configuration takes place in the form of environment vars.
|
138
|
-
See [queue_classic.rb](https://github.com/ryandotsmith/queue_classic/blob/master/lib/queue_classic.rb#
|
138
|
+
See [queue_classic.rb](https://github.com/ryandotsmith/queue_classic/blob/master/lib/queue_classic.rb#L23-62)
|
139
139
|
for a list of options.
|
140
140
|
|
141
141
|
## Usage
|
@@ -262,7 +262,7 @@ require "queue_classic"
|
|
262
262
|
QC::Worker.new.start
|
263
263
|
```
|
264
264
|
|
265
|
-
####
|
265
|
+
#### Subclass QC::Worker
|
266
266
|
|
267
267
|
Now that we have seen how to run a worker process, let's take a look at how to customize a worker.
|
268
268
|
The class `QC::Worker` will probably suit most of your needs; however, there are some mechanisms
|
@@ -278,7 +278,7 @@ class MyWorker < QC::Worker
|
|
278
278
|
|
279
279
|
# retry the job
|
280
280
|
def handle_failure(job, exception)
|
281
|
-
@queue.enqueue(job[:method], job[:args])
|
281
|
+
@queue.enqueue(job[:method], *job[:args])
|
282
282
|
end
|
283
283
|
|
284
284
|
# the forked proc needs a new db connection
|
@@ -444,24 +444,10 @@ database.
|
|
444
444
|
|
445
445
|
To achieve this we will create a helper method:
|
446
446
|
|
447
|
-
```ruby
|
448
|
-
|
449
|
-
def qc_txn
|
450
|
-
begin
|
451
|
-
QC.database.execute("BEGIN")
|
452
|
-
yield
|
453
|
-
QC.database.execute("COMMIT")
|
454
|
-
rescue Exception
|
455
|
-
QC.database.execute("ROLLBACK")
|
456
|
-
raise
|
457
|
-
end
|
458
|
-
end
|
459
|
-
```
|
460
|
-
|
461
447
|
Now in your application code you can do something like:
|
462
448
|
|
463
449
|
```ruby
|
464
|
-
|
450
|
+
QC::Conn.transaction do
|
465
451
|
Account.all.each do |act|
|
466
452
|
QC.enqueue("Emailer.send_notice", act.id)
|
467
453
|
end
|
@@ -579,3 +565,7 @@ $ createdb queue_classic_test
|
|
579
565
|
$ export QC_DATABASE_URL="postgres://username:pass@localhost/queue_classic_test"
|
580
566
|
$ rake
|
581
567
|
```
|
568
|
+
|
569
|
+
### License
|
570
|
+
|
571
|
+
queue_classic is released under the MIT License (http://www.opensource.org/licenses/mit-license.php).
|
data/test/queue_test.rb
CHANGED
@@ -56,4 +56,21 @@ class QueueTest < QCTest
|
|
56
56
|
assert_equal(0, queue.count)
|
57
57
|
end
|
58
58
|
|
59
|
+
def test_repair_after_error
|
60
|
+
queue = QC::Queue.new("queue_classic_jobs", false)
|
61
|
+
queue.enqueue("Klass.method")
|
62
|
+
assert_equal(1, queue.count)
|
63
|
+
connection = QC::Conn.connection
|
64
|
+
saved_method = connection.method(:exec)
|
65
|
+
def connection.exec(*args)
|
66
|
+
raise PGError
|
67
|
+
end
|
68
|
+
assert_raises(PG::Error) { queue.enqueue("Klass.other_method") }
|
69
|
+
assert_equal(1, queue.count)
|
70
|
+
queue.enqueue("Klass.other_method")
|
71
|
+
assert_equal(2, queue.count)
|
72
|
+
rescue PG::Error
|
73
|
+
QC::Conn.disconnect
|
74
|
+
assert false, "Expected to QC repair after connection error"
|
75
|
+
end
|
59
76
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: queue_classic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-07-23 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: pg
|
@@ -18,7 +18,7 @@ dependencies:
|
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: 0.
|
21
|
+
version: 0.14.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -26,7 +26,7 @@ dependencies:
|
|
26
26
|
requirements:
|
27
27
|
- - ~>
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: 0.
|
29
|
+
version: 0.14.0
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: scrolls
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -34,7 +34,7 @@ dependencies:
|
|
34
34
|
requirements:
|
35
35
|
- - ~>
|
36
36
|
- !ruby/object:Gem::Version
|
37
|
-
version: 0.
|
37
|
+
version: 0.2.1
|
38
38
|
type: :runtime
|
39
39
|
prerelease: false
|
40
40
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -42,7 +42,7 @@ dependencies:
|
|
42
42
|
requirements:
|
43
43
|
- - ~>
|
44
44
|
- !ruby/object:Gem::Version
|
45
|
-
version: 0.
|
45
|
+
version: 0.2.1
|
46
46
|
description: queue_classic is a queueing library for Ruby apps. (Rails, Sinatra, Etc...)
|
47
47
|
queue_classic features asynchronous job polling, database maintained locks and no
|
48
48
|
ridiculous dependencies. As a matter of fact, queue_classic only requires pg.
|
@@ -67,7 +67,8 @@ files:
|
|
67
67
|
- test/queue_test.rb
|
68
68
|
- test/worker_test.rb
|
69
69
|
homepage: http://github.com/ryandotsmith/queue_classic
|
70
|
-
licenses:
|
70
|
+
licenses:
|
71
|
+
- MIT
|
71
72
|
post_install_message:
|
72
73
|
rdoc_options: []
|
73
74
|
require_paths:
|