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 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")
@@ -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
 
@@ -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' && [: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
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
- u, size = uchardec(s, r)
483
- r += size - 1 # we add one more at the bottom of the loop
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
- # Decodes unicode character u from UTF-8
525
- # bytes in string s at position i.
526
- # Returns u and the number of bytes read.
527
- def uchardec(s, i)
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
- return [Ucharerr, 1] if n < 1
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
- return [c0, 1]
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
- return [Ucharerr, 1] if c1 < Utagx || Utag2 <= c1
519
+ raise Utf8Error if c1 < Utagx || Utag2 <= c1
545
520
 
546
521
  # 2-byte, 11-bit sequence?
547
522
  if c0 < Utag3
548
- u = (c0&Umask2)<<6 | (c1&Umaskx)
549
- return [Ucharerr, 1] if u <= Uchar1max
550
- return [u, 2]
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
- return [Ucharerr, 1] if n < 3
530
+ raise Utf8Error if n < 3
531
+
555
532
  c2 = s[i+2].ord
556
- return [Ucharerr, 1] if c2 < Utagx || Utag2 <= c2
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
- return [Ucharerr, 1] if u <= Uchar2max
562
- return [u, 3]
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
- return [Ucharerr, 1] if n < 4
546
+ raise Utf8Error if n < 4
567
547
  c3 = s[i+3].ord
568
- return [Ucharerr, 1] if c3 < Utagx || Utag2 <= c3
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
- return [Ucharerr, 1] if u <= Uchar3max
574
- return [u, 4]
575
- end
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
- return [Ucharerr, 1]
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
@@ -21,11 +21,11 @@ module QC
21
21
  end
22
22
 
23
23
  def delete_all
24
- Queries.delete_all(@name)
24
+ Queries.delete_all(name)
25
25
  end
26
26
 
27
27
  def count
28
- Queries.count(@name)
28
+ Queries.count(name)
29
29
  end
30
30
 
31
31
  end
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#L29-66)
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
- #### Sublcass QC::Worker
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
- qc_txn do
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.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-02-29 00:00:00.000000000 Z
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.13.2
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.13.2
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.0.8
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.0.8
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: