cirandas.net

ref: master

lib/noosfero/scheduler/defer.rb


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# based on https://github.com/discourse/discourse/blob/master/lib/scheduler/defer.rb

module Noosfero
  module Scheduler
    module Deferrable
      def initialize
        # FIXME: do some other way when not using Unicorn
        @async = (not Rails.env.test?) and defined? Unicorn
        @queue = Queue.new
        @mutex = Mutex.new
        @paused = false
        @thread = nil
      end

      def pause
        stop!
        @paused = true
      end

      def resume
        @paused = false
      end

      # for test
      def async= val
        @async = val
      end

      def later desc = nil, &blk
        if @async
          start_thread unless (@thread && @thread.alive?) || @paused
          @queue << [blk, desc]
        else
          blk.call
        end
      end

      def stop!
        @thread.kill if @thread and @thread.alive?
        @thread = nil
      end

      # test only
      def stopped?
        !(@thread and @thread.alive?)
      end

      def do_all_work
        while !@queue.empty?
          do_work _non_block=true
        end
      end

      private

      def start_thread
        @mutex.synchronize do
          return if @thread && @thread.alive?
          @thread = Thread.new do
            while true
              do_work
            end
          end
          @thread.priority = -2
        end
      end

      # using non_block to match Ruby #deq
      def do_work non_block=false
        job, desc = @queue.deq non_block
        begin
          job.call
        rescue => ex
          ExceptionNotifier.notify_exception ex, message: "Running deferred code '#{desc}'"
        end
      rescue => ex
        ExceptionNotifier.notify_exception ex, message: "Processing deferred code queue"
      end
    end

    class Defer

      module Unicorn
        def process_client client
          ::Noosfero::Scheduler::Defer.pause
          super client
          ::Noosfero::Scheduler::Defer.do_all_work
          ::Noosfero::Scheduler::Defer.resume
        end
      end

      extend Deferrable
      initialize
    end

  end
end