Commit 3449cc41 authored by Sam Wiskow's avatar Sam Wiskow
Browse files

Address MR review feedback: DX and reliability improvements

- Mark Evaluator as @api private
- Add KNOWN_ACTIONS constant documenting :block and :log
- Rename log_redis_error -> log_evaluate_error with comment clarifying
  the intentional broad rescue (fail-open for any unexpected error, not
  only Redis protocol errors)
- Memoize dev_or_test? to avoid ENV read on every call
- Add match: {} and action: :block defaults to Rule#initialize so callers
  only need to supply limit, period, and characteristics

Co-Authored-By: default avatarClaude Sonnet 4.6 <noreply@anthropic.com>
parent 752be81b
Loading
Loading
Loading
Loading
+10 −3
Original line number Diff line number Diff line
@@ -7,8 +7,10 @@ require "openssl"
module Labkit
  module RateLimit
    # Evaluator contains the core rule-matching + Redis counter logic.
    # @api private
    class Evaluator
      KNOWN_CHARACTERISTICS = [:user, :ip, :namespace, :plan, :endpoint].freeze
      KNOWN_ACTIONS = [:block, :log].freeze
      REDIS_KEY_PREFIX = "labkit:rl"
      CHAR_VALUE_MAX_LENGTH = 200
      UNKNOWN_SENTINEL = "unknown_characteristic"
@@ -28,7 +30,9 @@ module Labkit
      rescue ArgumentError
        raise
      rescue StandardError => e
        log_redis_error(e)
        # Intentionally broad: fail-open applies to any unexpected error (network,
        # timeout, OOM, etc.), not only Redis protocol errors.
        log_evaluate_error(e)
        :allow
      end

@@ -144,7 +148,7 @@ module Labkit
        @logger.info(JSON.generate(entry))
      end

      def log_redis_error(error)
      def log_evaluate_error(error)
        entry = {
          severity: "WARN",
          message: "rate_limit_redis_error",
@@ -156,8 +160,11 @@ module Labkit
      end

      def dev_or_test?
        # Memoized: ENV access is not free under concurrency.
        return @dev_or_test unless @dev_or_test.nil?

        env = ENV.fetch("LABKIT_ENV", nil)
        env == "test" || env == "development"
        @dev_or_test = env == "test" || env == "development"
      end

      def build_default_logger
+1 −1
Original line number Diff line number Diff line
@@ -4,7 +4,7 @@ module Labkit
  module RateLimit
    # Rule is a value object describing a single rate limit rule.
    Rule = Data.define(:match, :limit, :period, :action, :characteristics) do
      def initialize(match:, limit:, period:, action:, characteristics:)
      def initialize(limit:, period:, characteristics:, match: {}, action: :block)
        super(
          match: match.transform_keys(&:to_sym).freeze,
          limit: limit,