nagare-redis 0.4.0 → 0.5.0
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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +13 -0
- data/lib/nagare/config.rb +11 -3
- data/lib/nagare/listener_pool.rb +1 -3
- data/lib/nagare/redis_streams.rb +41 -4
- data/lib/nagare/version.rb +1 -1
- metadata +3 -3
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: a74be4520fe261310cc782a2232ad5270ed572c4afbd98072241ef6dc1bc118c
         | 
| 4 | 
            +
              data.tar.gz: f3d9391aae29591f9652e342034ce79959498a020596b01a4d4c3d40bf35d33a
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: b9c5c5bfa26746f5a0d5c84446991aad2d3d3faf802e8c9222d61fb79b6f2aaecdf55b81654ec71571c5d978d1350bb8306c054db2e816106c9a730383c2b9e6
         | 
| 7 | 
            +
              data.tar.gz: a973dc7583907a0b75d0c8e09dda57e799721eab302a3d1786e0c83293c1475baa37cbea8ccc3dbb36fd39a45e4c906bac33dea2b4980a36c7a733b7a919f96f
         | 
    
        data/Gemfile.lock
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -67,6 +67,19 @@ Nagare.configure do |config| | |
| 67 67 | 
             
              # and in the background
         | 
| 68 68 | 
             
              # Default: 3 threads
         | 
| 69 69 | 
             
              config.threads = 3
         | 
| 70 | 
            +
             | 
| 71 | 
            +
              # Nagare can execute a proc for error handling. This enables you to
         | 
| 72 | 
            +
              # use APM tools like New Relic or Appsignal with it.
         | 
| 73 | 
            +
              # The proc takes 2 parameters, message and error.
         | 
| 74 | 
            +
              # By default, nagare logs the error to stderr.
         | 
| 75 | 
            +
              config.error_handler = proc do |message, error|
         | 
| 76 | 
            +
                Appsignal.set_error(error);
         | 
| 77 | 
            +
              end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
              # After exceeding the maximum number of retries, nagare moves the
         | 
| 80 | 
            +
              # failing messages to a Dead Letter Queue stream. 
         | 
| 81 | 
            +
              # By default this stream is named 'dlq', but you can customize it.
         | 
| 82 | 
            +
              config.dlq_stream = 'its_dead_jim'
         | 
| 70 83 | 
             
            end
         | 
| 71 84 | 
             
            ```
         | 
| 72 85 |  | 
    
        data/lib/nagare/config.rb
    CHANGED
    
    | @@ -5,13 +5,14 @@ module Nagare | |
| 5 5 | 
             
              # See the README for possible values and what they do
         | 
| 6 6 | 
             
              class Config
         | 
| 7 7 | 
             
                class << self
         | 
| 8 | 
            -
                  attr_accessor :group_name, :redis_url, :threads, :suffix, :min_idle_time
         | 
| 8 | 
            +
                  attr_accessor :group_name, :redis_url, :threads, :suffix, :min_idle_time,
         | 
| 9 | 
            +
                                :error_handler, :dlq_stream, :max_retries
         | 
| 9 10 |  | 
| 10 11 | 
             
                  # Runs code in the block passed in to configure Nagare and sets defaults
         | 
| 11 12 | 
             
                  # when values are not set.
         | 
| 12 13 | 
             
                  #
         | 
| 13 14 | 
             
                  # returns [Nagare::Config] self
         | 
| 14 | 
            -
                  # rubocop:disable Metrics/CyclomaticComplexity
         | 
| 15 | 
            +
                  # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength, Metrics/AbcSize
         | 
| 15 16 | 
             
                  def configure
         | 
| 16 17 | 
             
                    yield(self)
         | 
| 17 18 | 
             
                    @dead_consumer_timeout ||= 5000
         | 
| @@ -20,9 +21,16 @@ module Nagare | |
| 20 21 | 
             
                    @threads ||= 1
         | 
| 21 22 | 
             
                    @suffix ||= nil
         | 
| 22 23 | 
             
                    @min_idle_time ||= 600_000
         | 
| 24 | 
            +
                    @error_handler ||= proc do |message, error|
         | 
| 25 | 
            +
                      Nagare.logger.error "Failed to process message #{message}"
         | 
| 26 | 
            +
                      Nagare.logger.error error.message
         | 
| 27 | 
            +
                      Nagare.logger.error error.backtrace.join("\n")
         | 
| 28 | 
            +
                    end
         | 
| 29 | 
            +
                    @dlq_stream ||= 'dlq'
         | 
| 30 | 
            +
                    @max_retries ||= 10
         | 
| 23 31 | 
             
                    self
         | 
| 24 32 | 
             
                  end
         | 
| 25 | 
            -
                  # rubocop:enable Metrics/CyclomaticComplexity
         | 
| 33 | 
            +
                  # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength, Metrics/AbcSize
         | 
| 26 34 | 
             
                end
         | 
| 27 35 | 
             
              end
         | 
| 28 36 | 
             
            end
         | 
    
        data/lib/nagare/listener_pool.rb
    CHANGED
    
    | @@ -83,10 +83,8 @@ module Nagare | |
| 83 83 | 
             
                    listeners.each do |listener|
         | 
| 84 84 | 
             
                      invoke_listener(stream, message, listener)
         | 
| 85 85 | 
             
                    rescue StandardError => e
         | 
| 86 | 
            -
                      logger.error e.message
         | 
| 87 | 
            -
                      logger.error e.backtrace.join("\n")
         | 
| 88 86 | 
             
                      listener_failed = true
         | 
| 89 | 
            -
                       | 
| 87 | 
            +
                      Nagare::Config.error_handler.call(message, e)
         | 
| 90 88 | 
             
                    end
         | 
| 91 89 |  | 
| 92 90 | 
             
                    return if listener_failed
         | 
    
        data/lib/nagare/redis_streams.rb
    CHANGED
    
    | @@ -76,27 +76,64 @@ module Nagare | |
| 76 76 | 
             
                  # @return [String] message id
         | 
| 77 77 | 
             
                  def publish(stream, event_name, data)
         | 
| 78 78 | 
             
                    stream = stream_name(stream)
         | 
| 79 | 
            -
                    connection.xadd(stream, { "#{event_name}": data })
         | 
| 79 | 
            +
                    connection.xadd(stream, { "#{event_name}": data.to_json })
         | 
| 80 80 | 
             
                  end
         | 
| 81 81 |  | 
| 82 82 | 
             
                  ##
         | 
| 83 83 | 
             
                  # Claums the next message of the consumer group that is stuck
         | 
| 84 84 | 
             
                  # (pending and past min_idle_time since being picked up)
         | 
| 85 85 | 
             
                  #
         | 
| 86 | 
            -
                  # @param  | 
| 86 | 
            +
                  # @param stream_prefix [String] name of the stream
         | 
| 87 87 | 
             
                  # @param group [String] name of the consumer group
         | 
| 88 88 | 
             
                  #
         | 
| 89 89 | 
             
                  # @return [Array[Hash]] array containing the 1 message or empty
         | 
| 90 | 
            -
                   | 
| 91 | 
            -
             | 
| 90 | 
            +
                  # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
         | 
| 91 | 
            +
                  def claim_next_stuck_message(stream_prefix, group)
         | 
| 92 | 
            +
                    stream = stream_name(stream_prefix)
         | 
| 92 93 | 
             
                    result = connection.xautoclaim(stream,
         | 
| 93 94 | 
             
                                                   "#{stream}-#{group}",
         | 
| 94 95 | 
             
                                                   "#{hostname}-#{thread_id}",
         | 
| 95 96 | 
             
                                                   Nagare::Config.min_idle_time,
         | 
| 96 97 | 
             
                                                   '0-0',
         | 
| 97 98 | 
             
                                                   count: 1)
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                    # Move message to DLQ if retried too much and get next one
         | 
| 101 | 
            +
                    if result['entries'].any?
         | 
| 102 | 
            +
                      message_id = result['entries'].first.first
         | 
| 103 | 
            +
                      if retry_count(stream_prefix, group,
         | 
| 104 | 
            +
                                     message_id) > Nagare::Config.max_retries
         | 
| 105 | 
            +
                        move_to_dlq(stream_prefix, group, result['entries'].first)
         | 
| 106 | 
            +
                        return claim_next_stuck_message(stream, group)
         | 
| 107 | 
            +
                      end
         | 
| 108 | 
            +
                    end
         | 
| 109 | 
            +
             | 
| 98 110 | 
             
                    result['entries'] || []
         | 
| 99 111 | 
             
                  end
         | 
| 112 | 
            +
                  # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
         | 
| 113 | 
            +
             | 
| 114 | 
            +
                  ##
         | 
| 115 | 
            +
                  # Uses XPENDING to verify the number of times the message was
         | 
| 116 | 
            +
                  # delivered
         | 
| 117 | 
            +
                  def retry_count(stream, group, message_id)
         | 
| 118 | 
            +
                    stream = stream_name(stream)
         | 
| 119 | 
            +
                    result = connection.xpending(stream,
         | 
| 120 | 
            +
                                                 "#{stream}-#{group}",
         | 
| 121 | 
            +
                                                 message_id,
         | 
| 122 | 
            +
                                                 message_id,
         | 
| 123 | 
            +
                                                 1)
         | 
| 124 | 
            +
                    return 0 unless result.any?
         | 
| 125 | 
            +
             | 
| 126 | 
            +
                    result.first['count']
         | 
| 127 | 
            +
                  end
         | 
| 128 | 
            +
             | 
| 129 | 
            +
                  ##
         | 
| 130 | 
            +
                  # Moves a message to the dead letter queue stream
         | 
| 131 | 
            +
                  def move_to_dlq(stream, group, message)
         | 
| 132 | 
            +
                    Nagare.logger.warn "Moving message to DLQ #{message} \
         | 
| 133 | 
            +
                                        from stream #{stream}"
         | 
| 134 | 
            +
                    publish(Nagare::Config.dlq_stream, stream, message)
         | 
| 135 | 
            +
                    mark_processed(stream, group, message.first)
         | 
| 136 | 
            +
                  end
         | 
| 100 137 |  | 
| 101 138 | 
             
                  ##
         | 
| 102 139 | 
             
                  # Reads the next messages from the consumer group in redis.
         | 
    
        data/lib/nagare/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: nagare-redis
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.5.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Alex Reis
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: exe
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2021- | 
| 11 | 
            +
            date: 2021-09-09 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: redis
         | 
| @@ -124,7 +124,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 124 124 | 
             
                - !ruby/object:Gem::Version
         | 
| 125 125 | 
             
                  version: '0'
         | 
| 126 126 | 
             
            requirements: []
         | 
| 127 | 
            -
            rubygems_version: 3.0.3 | 
| 127 | 
            +
            rubygems_version: 3.0.3
         | 
| 128 128 | 
             
            signing_key: 
         | 
| 129 129 | 
             
            specification_version: 4
         | 
| 130 130 | 
             
            summary: Persistent and resilient pub/sub using Redis Streams
         |