gruf-queue 0.1.1 → 0.1.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b0aed8b2822b571278254b3fa5838fcee2bd1c709ce7397bf4dbe9fc296f8847
4
- data.tar.gz: e4972e7017721f7c6d1f2924c6b362bb0bb08705b4ef63b31f9ee2465904d953
3
+ metadata.gz: 93e75c950c181dceecb26c7bb037014232fb190602c85800702c6b8bf29329c7
4
+ data.tar.gz: a81edb2a6d96d1c514c850b20ed0422eeed701e296497149df0e57597cc1875e
5
5
  SHA512:
6
- metadata.gz: '09802fce427e339133d11fd72776a61061334e0b29e38e28628a636948830b48280fdc6b89e60dedad2e4a6fcce6355e21c1c1c79ff3c27691697f4eac560624'
7
- data.tar.gz: 26ae3647141bc9bee23607743bc94c19f42a2b7bd81bf3a9440c3bd6f86d01122c1b4e5f81144ee6a009595aa445e685cc7f33bba5fdf604a07acacb013182df
6
+ metadata.gz: 6d6f81af6800c4f8aca41a5400609e147b011b24ae9c6864b3caede6492889e7b9b8e9912274828f9bb35f57793b93355a50b918527d9383b3a719ad7346e509
7
+ data.tar.gz: e4efc9c13fe4c3867f65312175f65896e6dcd1f65c52ecbec99727ccb2a62e3c4f527ba7afc941ff3ec53faa9c212175b28bf286f753eee6190e47119eb41cc4
data/CHANGELOG.md CHANGED
@@ -5,7 +5,36 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
- ## [0.1.0] - 2024-01-01
8
+ ## [0.1.2]
9
+
10
+ ### Changed
11
+ - **BREAKING**: Simplified logging system by removing custom log helpers
12
+ - Removed all custom logging methods (log_structured, log_debug, log_error)
13
+ - Simplified error handling to use Gruf.logger directly only where critical
14
+ - Eliminated redundant logging as it's not the gem's responsibility
15
+ - Removed excessive YARD documentation and inline comments for better readability
16
+ - Replaced const replacement with safer module prepend pattern
17
+ - Enhanced GRPC::Pool using PoolEnhancements module without class replacement
18
+ - Improved error handling and recovery mechanisms
19
+ - Updated test suite to handle new module prepend architecture
20
+
21
+ ### Improved
22
+ - Code is now more readable with essential documentation only
23
+ - Reduced complexity following single responsibility principle
24
+ - Applications handle their own logging strategy
25
+ - Fixed all rubocop style issues
26
+
27
+ ### Fixed
28
+ - **CRITICAL**: Fixed parameter passing to parent GRPC::RpcServer class
29
+ - Fixed Rails initialization timing issues with auto-install
30
+ - Fixed thread pool management with proper parameter inheritance
31
+
32
+ ### Added
33
+ - PoolEnhancements module for clean GRPC::Pool extension
34
+ - Improved thread safety and pool management
35
+ - Better error isolation in worker threads
36
+
37
+ ## [0.1.0]
9
38
 
10
39
  ### Added
11
40
  - Initial release of gruf-queue
@@ -28,4 +57,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
28
57
  - **Observability**: Structured logging with metadata for monitoring and debugging
29
58
  - **Customization**: Flexible configuration options for different deployment scenarios
30
59
 
31
- [0.1.0]: https://github.com/ether-moon/gruf-queue/releases/tag/v0.1.0
60
+ [0.1.0]: https://github.com/ether-moon/gruf-queue/releases/tag/v0.1.0
@@ -12,10 +12,6 @@ module Gruf
12
12
  module Configuration
13
13
  module_function
14
14
 
15
- # Apply queue-specific configuration to Gruf.
16
- #
17
- # @return [void]
18
- # @raise [StandardError] if configuration fails
19
15
  def configure
20
16
  return if configured?
21
17
 
@@ -25,83 +21,44 @@ module Gruf
25
21
  end
26
22
 
27
23
  @configured = true
28
- log_debug('Gruf configuration enhanced with rpc_server support', version: Gruf::Queue::VERSION)
29
24
  rescue StandardError => e
30
- log_error('Failed to enhance Gruf configuration', error: e.message, error_class: e.class.name)
25
+ if defined?(Gruf) && Gruf.respond_to?(:logger)
26
+ Gruf.logger.error("Failed to enhance Gruf configuration: #{e.message}")
27
+ end
31
28
  raise
32
29
  end
33
30
  end
34
31
 
35
- # Check if configuration has been applied.
36
- #
37
- # @return [Boolean] true if configured, false otherwise
38
32
  def configured?
39
33
  !!@configured
40
34
  end
41
35
 
42
- # Reset configuration state for testing.
43
- #
44
- # @return [void]
45
- # @raise [RuntimeError] if not in test environment
46
36
  def reset!
47
37
  raise 'reset! can only be called in test environments' unless test_environment?
48
38
 
49
39
  @configured = false
50
40
 
51
- # Reset Gruf configuration to clean state
52
- if defined?(Gruf) && Gruf.respond_to?(:configuration)
53
- config = Gruf.configuration
54
- config.rpc_server = nil if config.respond_to?(:rpc_server=)
55
- end
41
+ return unless defined?(Gruf) && Gruf.respond_to?(:configuration)
56
42
 
57
- log_debug('Gruf configuration state reset', reason: 'test_environment')
43
+ config = Gruf.configuration
44
+ config.rpc_server = nil if config.respond_to?(:rpc_server=)
58
45
  end
59
46
 
60
- # Enhance Gruf configuration with rpc_server support
61
47
  def enhance_gruf_configuration(config)
62
48
  config.define_singleton_method(:rpc_server) { @rpc_server }
63
49
  config.define_singleton_method(:rpc_server=) { |val| @rpc_server = val }
64
50
  config.rpc_server = nil unless config.respond_to?(:rpc_server)
65
51
 
66
- # Make the configuration accessible via Gruf.configuration if not already available
67
52
  return if Gruf.respond_to?(:configuration)
68
53
 
69
54
  Gruf.define_singleton_method(:configuration) { config }
70
55
  end
71
56
 
72
- # Check if running in test environment
73
57
  def test_environment?
74
58
  ENV['RACK_ENV'] == 'test' ||
75
59
  ENV['RAILS_ENV'] == 'test' ||
76
60
  defined?(RSpec)
77
61
  end
78
-
79
- # Log debug message
80
- def log_debug(message, **metadata)
81
- return unless defined?(Gruf) && Gruf.respond_to?(:logger)
82
-
83
- if metadata.any?
84
- Gruf.logger.debug(metadata.merge(message: message))
85
- else
86
- Gruf.logger.debug(message)
87
- end
88
- rescue StandardError
89
- # Ignore logging errors
90
- end
91
-
92
- # Log error message
93
- def log_error(message, **metadata)
94
- return unless defined?(Gruf) && Gruf.respond_to?(:logger)
95
- return if test_environment? # Skip error logging in test environment
96
-
97
- if metadata.any?
98
- Gruf.logger.error(metadata.merge(message: message))
99
- else
100
- Gruf.logger.error(message)
101
- end
102
- rescue StandardError
103
- # Ignore logging errors
104
- end
105
62
  end
106
63
  end
107
64
  end
@@ -14,145 +14,73 @@ module Gruf
14
14
  # target_classes: [ActiveRecord::Base]
15
15
  # )
16
16
  class ConnectionReset < ::Gruf::Interceptors::ServerInterceptor
17
- # Initialize interceptor with request context and options.
18
- #
19
- # @param request [Object] gRPC request object
20
- # @param call [Object] gRPC call object
21
- # @param method [Object] gRPC method object
22
- # @param options [Hash] Configuration options
23
- # @option options [Boolean] :enabled (true) Enable/disable interceptor
24
- # @option options [Array<Class>] :target_classes Classes to reset connections for
25
17
  def initialize(request, call, method, options = {})
26
18
  @request = request
27
19
  @call = call
28
20
  @method = method
29
21
  @options = options || {}
30
- # Set default enabled value if not provided
31
22
  @options[:enabled] = true unless @options.key?(:enabled)
32
23
  end
33
24
 
34
- # Execute request and reset connections on completion.
35
- #
36
- # @yield Block containing the actual request handling
37
- # @return [Object] Result of yielded block
38
25
  def call
39
26
  yield
40
27
  ensure
41
28
  begin
42
29
  reset_connections if enabled?
43
- rescue StandardError => e
44
- # Log error but don't prevent handler execution
45
- log_message(:error, "Connection reset failed: #{e.message}")
30
+ rescue StandardError
31
+ # Ignore connection reset errors silently
46
32
  end
47
33
  end
48
34
 
49
35
  private
50
36
 
51
- # Get interceptor configuration options.
52
- #
53
- # @return [Hash] Configuration options
54
37
  attr_reader :options
55
38
 
56
- # Check if interceptor is enabled and has valid target classes.
57
- #
58
- # @return [Boolean] true if should execute, false otherwise
59
39
  def enabled?
60
- # Check if explicitly disabled
61
40
  return false if options[:enabled] == false
62
-
63
- # If no target classes are provided and ActiveRecord is not available, disable
64
41
  return false if target_classes.empty?
65
42
 
66
43
  true
67
44
  end
68
45
 
69
- # Reset connections for all valid target classes.
70
- #
71
- # @return [void]
72
46
  def reset_connections
73
47
  validated_classes = validate_target_classes
74
48
  return if validated_classes.empty?
75
49
 
76
- reset_count = 0
77
50
  validated_classes.each do |klass|
78
- reset_count += 1 if reset_connection_for_class(klass)
51
+ reset_connection_for_class(klass)
79
52
  end
80
-
81
- log_reset_summary(reset_count, validated_classes.size) if reset_count.positive?
82
53
  end
83
54
 
84
55
  def target_classes
85
- # Use instance variable if set (for testing)
86
56
  return Array(@target_classes).compact if instance_variable_defined?(:@target_classes)
87
57
 
88
- # Otherwise use options or default
89
58
  default_classes = defined?(::ActiveRecord::Base) ? [::ActiveRecord::Base] : []
90
59
  classes = options.fetch(:target_classes, default_classes)
91
60
  Array(classes).compact
92
61
  end
93
62
 
94
- # Validate and filter target classes to ensure they support connection handling
95
63
  def validate_target_classes
96
64
  target_classes.select do |klass|
97
65
  valid_class?(klass)
98
66
  end
99
67
  end
100
68
 
101
- # Check if a class is valid for connection reset capability
102
69
  def valid_class?(klass)
103
- unless klass.is_a?(Class)
104
- log_validation_warning(klass, 'not a class')
105
- return false
106
- end
107
-
108
- unless klass.respond_to?(:connection_handler)
109
- log_validation_warning(klass, 'does not respond to connection_handler')
110
- return false
111
- end
70
+ return false unless klass.is_a?(Class)
71
+ return false unless klass.respond_to?(:connection_handler)
112
72
 
113
73
  true
114
74
  end
115
75
 
116
- # Reset connections for a single class
117
76
  def reset_connection_for_class(klass)
118
77
  handler = klass.connection_handler
119
78
  handler.clear_active_connections!(:all) if handler.respond_to?(:clear_active_connections!)
120
79
  handler.clear_reloadable_connections! if handler.respond_to?(:clear_reloadable_connections!)
121
80
  true
122
- rescue StandardError => e
123
- log_reset_error(klass, e)
81
+ rescue StandardError
124
82
  false
125
83
  end
126
-
127
- # Log validation warnings
128
- def log_validation_warning(klass, reason)
129
- message = "Skipping connection reset for #{klass.inspect}: #{reason}"
130
- log_message(:debug, message)
131
- end
132
-
133
- # Log connection reset errors
134
- def log_reset_error(klass, error)
135
- message = "Failed to reset connections for #{klass}: #{error.message}"
136
- log_message(:warn, message)
137
- end
138
-
139
- # Log reset operation summary
140
- def log_reset_summary(reset_count, total_count)
141
- message = "Reset connections for #{reset_count}/#{total_count} classes"
142
- log_message(:debug, message)
143
- end
144
-
145
- # Centralized logging with fallback chain
146
- def log_message(level, message)
147
- if defined?(Rails) && Rails.logger.respond_to?(level)
148
- Rails.logger.public_send(level, message)
149
- elsif defined?(GRPC) && GRPC.logger.respond_to?(level)
150
- GRPC.logger.public_send(level, message)
151
- elsif level == :warn
152
- # Fallback to stderr for critical messages
153
- warn(message)
154
- end
155
- end
156
84
  end
157
85
  end
158
86
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'pool_enhancements'
4
+
3
5
  module Gruf
4
6
  module Queue
5
7
  # Plugin management for gruf-queue integration.
@@ -14,18 +16,12 @@ module Gruf
14
16
  # Gruf::Queue::Plugin.installed? # => true
15
17
  class Plugin
16
18
  class << self
17
- # Install and configure the gruf-queue plugin.
18
- # This method is idempotent and can be called multiple times safely.
19
- #
20
- # @return [Boolean] true if installation completed, false if already installed
21
19
  def install!
22
20
  return false if @installed
23
21
 
24
22
  begin
25
- # Configure Gruf with queue-specific settings
26
23
  Configuration.configure unless Configuration.configured?
27
-
28
- # Configure Gruf with all queue-specific settings
24
+ enhance_grpc_pool
29
25
  Gruf.configure do |config|
30
26
  configure_rpc_server(config)
31
27
  configure_interceptors(config)
@@ -33,45 +29,26 @@ module Gruf
33
29
 
34
30
  @installed = true
35
31
  true
36
- rescue StandardError => e
37
- # Log the error but don't raise to avoid breaking the application startup
38
- log_installation_error(e)
32
+ rescue StandardError
39
33
  false
40
34
  end
41
35
  end
42
36
 
43
- # Check installation status.
44
- #
45
- # @return [Boolean] true if installed, false otherwise
46
37
  def installed?
47
38
  !!@installed
48
39
  end
49
40
 
50
- # Reset installation state for testing.
51
- #
52
- # @return [void]
53
41
  def reset!
54
42
  @installed = false
55
- # Also reset the configuration state
56
43
  Configuration.reset! if Configuration.respond_to?(:reset!)
57
44
  end
58
45
 
59
46
  private
60
47
 
61
- # Configure RPC server to use QueuedRpcServer.
62
- #
63
- # @param config [Object] Gruf configuration object
64
- # @return [void]
65
- # @api private
66
48
  def configure_rpc_server(config)
67
49
  config.rpc_server = QueuedRpcServer
68
50
  end
69
51
 
70
- # Configure interceptors if ActiveRecord is available.
71
- #
72
- # @param config [Object] Gruf configuration object
73
- # @return [void]
74
- # @api private
75
52
  def configure_interceptors(config)
76
53
  return unless defined?(ActiveRecord)
77
54
 
@@ -85,31 +62,15 @@ module Gruf
85
62
  )
86
63
  end
87
64
 
88
- # Validate ActiveRecord connection handler availability.
89
- #
90
- # @raise [StandardError] if ActiveRecord doesn't support connection_handler
91
- # @return [void]
92
- # @api private
93
65
  def validate_active_record_availability
94
66
  return if ActiveRecord::Base.respond_to?(:connection_handler)
95
67
 
96
68
  raise StandardError, 'ActiveRecord::Base does not support connection_handler'
97
69
  end
98
70
 
99
- # Ensure interceptors registry is available and initialized.
100
- #
101
- # Handles Rails initialization timing issues where gruf-queue loads
102
- # before Gruf's configuration is fully initialized.
103
- #
104
- # @param config [Object] Gruf configuration object
105
- # @return [void]
106
- # @raise [StandardError] if interceptors registry cannot be initialized
107
- # @api private
108
71
  def ensure_interceptors_registry_available(config)
109
- # Check if interceptors registry exists and is initialized
110
72
  return if config.respond_to?(:interceptors) && !config.interceptors.nil?
111
73
 
112
- # Initialize interceptors registry if missing
113
74
  begin
114
75
  require 'gruf/interceptors/registry'
115
76
  rescue LoadError => e
@@ -119,7 +80,6 @@ module Gruf
119
80
  if config.respond_to?(:interceptors=)
120
81
  config.interceptors = ::Gruf::Interceptors::Registry.new
121
82
  elsif config.respond_to?(:define_singleton_method)
122
- # Fallback: define interceptors accessor methods dynamically
123
83
  registry = ::Gruf::Interceptors::Registry.new
124
84
  config.define_singleton_method(:interceptors) { registry }
125
85
  config.define_singleton_method(:interceptors=) { |val| registry = val }
@@ -127,30 +87,15 @@ module Gruf
127
87
  raise StandardError, 'Cannot initialize interceptors registry: configuration object lacks required methods'
128
88
  end
129
89
 
130
- # Verify initialization was successful
131
90
  return if config.respond_to?(:interceptors) && config.interceptors.respond_to?(:use)
132
91
 
133
92
  raise StandardError, 'Interceptors registry initialization failed: missing use method'
134
93
  end
135
94
 
136
- # Log installation error using available logger.
137
- #
138
- # @param error [StandardError] Error to log
139
- # @return [void]
140
- # @api private
141
- def log_installation_error(error)
142
- message = "Failed to install gruf-queue plugin: #{error.message}"
143
-
144
- # Skip error logging in test environment
145
- return if ENV['RACK_ENV'] == 'test' || ENV['RAILS_ENV'] == 'test' || defined?(RSpec)
146
-
147
- if defined?(Rails) && Rails.logger.respond_to?(:error)
148
- Rails.logger.error(message)
149
- elsif defined?(GRPC) && GRPC.logger.respond_to?(:error)
150
- GRPC.logger.error(message)
151
- else
152
- warn message
153
- end
95
+ def enhance_grpc_pool
96
+ return if ::GRPC::Pool.included_modules.include?(Gruf::Queue::PoolEnhancements)
97
+
98
+ ::GRPC::Pool.prepend(Gruf::Queue::PoolEnhancements)
154
99
  end
155
100
  end
156
101
  end
@@ -15,141 +15,74 @@ module Gruf
15
15
  # Default keep-alive time for worker threads (in seconds)
16
16
  DEFAULT_KEEP_ALIVE = 600
17
17
 
18
- # Initialize pool with specified size and keep-alive time.
19
- #
20
- # @param size [Integer] Number of worker threads to maintain
21
- # @param keep_alive [Integer] Thread keep-alive time in seconds
22
18
  def initialize(size, keep_alive: DEFAULT_KEEP_ALIVE)
23
19
  super
24
20
  end
25
21
 
26
- # Get number of jobs currently waiting in queue.
27
- #
28
- # @return [Integer] Count of queued jobs
29
22
  def jobs_waiting
30
23
  @jobs&.size || 0
31
24
  end
32
25
 
33
- # Schedule block for execution on worker thread.
34
- #
35
- # @param args [Array] Arguments to pass to block
36
- # @param blk [Proc] Block to execute
37
- # @return [Boolean] true if scheduled, false if stopped or nil block
38
26
  def schedule(*args, &blk)
39
27
  return false if blk.nil?
40
28
 
41
29
  @stop_mutex.synchronize do
42
- if @stopped
43
- log_structured(:warn, 'Job scheduling rejected: pool already stopped')
44
- return false
45
- end
46
- log_structured(:debug, 'Job scheduled for execution')
30
+ return false if @stopped
47
31
 
48
32
  @jobs << [blk, args]
49
33
  true
50
34
  end
51
- rescue StandardError => e
52
- log_structured(:error, 'Failed to schedule job', error: e.message)
35
+ rescue StandardError
53
36
  false
54
37
  end
55
38
 
56
- # Start thread pool and create worker threads.
57
- #
58
- # @raise [RuntimeError] if pool is already stopped
59
- # @return [void]
60
39
  def start
61
40
  @stop_mutex.synchronize do
62
41
  raise 'Pool already stopped' if @stopped
63
42
  end
64
43
 
65
44
  target_size = @size.to_i
66
- log_structured(:info, 'Starting thread pool', target_size: target_size)
67
45
 
68
46
  until @workers.size == target_size
69
47
  next_thread = create_worker_thread
70
48
  @workers << next_thread if next_thread
71
49
  end
72
-
73
- log_structured(:info, 'Thread pool started', worker_count: @workers.size)
74
- rescue StandardError => e
75
- log_structured(:error, 'Failed to start thread pool', error: e.message)
76
- raise
77
50
  end
78
51
 
79
52
  protected
80
53
 
81
- # Create new worker thread with error handling.
82
- #
83
- # @return [Thread, nil] Worker thread or nil on error
84
54
  def create_worker_thread
85
55
  Thread.new do
86
56
  catch(:exit) do
87
- # allows { throw :exit } to kill a thread
88
57
  _loop_execute_jobs
89
58
  end
90
59
  remove_current_thread
91
60
  end
92
- rescue StandardError => e
93
- log_structured(:error, 'Failed to create worker thread', error: e.message)
61
+ rescue StandardError
94
62
  nil
95
63
  end
96
64
 
97
- # Main worker thread loop for job execution.
98
- #
99
- # @return [void]
100
- # @api private
101
65
  def _loop_execute_jobs
102
66
  Thread.current.name = "gruf-queue-worker-#{Thread.current.object_id}"
103
- log_structured(:debug, 'Worker thread started', thread_id: Thread.current.object_id)
104
67
 
105
68
  loop do
106
69
  begin
107
70
  blk, args = @jobs.pop
108
71
  execute_job_safely(blk, args)
109
- rescue StandardError => e
110
- log_structured(:error, 'Unexpected error in worker thread',
111
- error: e.message,
112
- backtrace: e.backtrace&.first(5))
72
+ rescue ThreadError, SystemStackError, IOError
73
+ # Ignore system-level errors to prevent worker thread death
113
74
  end
114
75
 
115
76
  @stop_mutex.synchronize do
116
77
  return if @stopped
117
78
  end
118
79
  end
119
- ensure
120
- log_structured(:debug, 'Worker thread stopping', thread_id: Thread.current.object_id)
121
80
  end
122
81
 
123
- # Execute job with error isolation and logging.
124
- #
125
- # @param blk [Proc] Job block to execute
126
- # @param args [Array] Arguments for the block
127
- # @return [void]
128
82
  def execute_job_safely(blk, args)
129
83
  blk.call(*args)
130
- rescue StandardError, GRPC::Core::CallError => e
131
- log_structured(:warn, 'Job execution failed',
132
- error: e.message,
133
- error_class: e.class.name)
134
- # Log full backtrace only in debug mode to avoid log spam
135
- log_structured(:debug, 'Job execution backtrace', backtrace: e.backtrace) if e.backtrace
136
- end
137
-
138
- # Log message with structured metadata.
139
- #
140
- # @param level [Symbol] Log level (:info, :warn, :error, :debug)
141
- # @param message [String] Base log message
142
- # @param metadata [Hash] Additional metadata to include
143
- # @return [void]
144
- def log_structured(level, message, **metadata)
145
- return unless GRPC.logger.respond_to?(level)
146
-
147
- if metadata.any?
148
- formatted_message = "#{message} #{metadata.map { |k, v| "#{k}=#{v}" }.join(' ')}"
149
- GRPC.logger.public_send(level, formatted_message)
150
- else
151
- GRPC.logger.public_send(level, message)
152
- end
84
+ rescue SystemStackError, IOError, GRPC::Core::CallError, GRPC::BadStatus, Timeout::Error
85
+ # Ignore system/network/gRPC errors to prevent worker thread death
153
86
  end
154
87
  end
155
88
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gruf
4
+ module Queue
5
+ # Enhanced functionality for GRPC::Pool without intrusive modifications.
6
+ #
7
+ # Provides essential queue management features while preserving the original
8
+ # GRPC::Pool class structure and inheritance hierarchy.
9
+ #
10
+ # @example Usage
11
+ # GRPC::Pool.prepend(Gruf::Queue::PoolEnhancements)
12
+ module PoolEnhancements
13
+ def jobs_waiting
14
+ @jobs&.size || 0
15
+ end
16
+
17
+ def schedule(*args, &blk)
18
+ return false if blk.nil?
19
+
20
+ super
21
+ rescue StandardError
22
+ false
23
+ end
24
+ end
25
+ end
26
+ end
@@ -30,32 +30,19 @@ module Gruf
30
30
  # Error message for resource exhaustion
31
31
  RESOURCE_EXHAUSTED_MESSAGE = 'No free threads in thread pool'
32
32
 
33
- # Initialize the QueuedRpcServer with custom pool settings.
34
- #
35
- # @param pool_size [Integer] Number of worker threads in the pool
36
- # @param max_waiting_requests [Integer] Maximum requests to queue before rejecting
37
- # @param pool_keep_alive [Integer] Thread keep-alive time in seconds
38
- # @param poll_period [Integer] Server polling interval in seconds
39
- # @param args [Hash] Additional arguments passed to GRPC::RpcServer
40
33
  def initialize(pool_size: DEFAULT_POOL_SIZE,
41
34
  max_waiting_requests: DEFAULT_MAX_WAITING_REQUESTS,
42
35
  pool_keep_alive: Pool::DEFAULT_KEEP_ALIVE,
43
36
  poll_period: DEFAULT_POLL_PERIOD,
44
37
  **args)
45
- super(**args)
38
+ super
46
39
 
47
40
  @pool_size = pool_size
48
41
  @max_waiting_requests = max_waiting_requests
49
42
  @pool_keep_alive = pool_keep_alive
50
43
  @poll_period = poll_period
51
-
52
- @pool = Gruf::Queue::Pool.new(@pool_size, keep_alive: @pool_keep_alive)
53
44
  end
54
45
 
55
- # Check if server can handle the request based on current queue load.
56
- #
57
- # @param an_rpc [Object] The incoming RPC request
58
- # @return [Object, false] The RPC if available, false if resource exhausted
59
46
  def available?(an_rpc)
60
47
  job_count = safe_job_count
61
48
  return an_rpc if job_count < @max_waiting_requests
@@ -66,26 +53,19 @@ module Gruf
66
53
 
67
54
  private
68
55
 
69
- # Get current job count from pool with error handling.
70
- #
71
- # @return [Integer] Number of jobs waiting, or max_waiting_requests on error
72
56
  def safe_job_count
57
+ return 0 unless @pool
58
+
73
59
  @pool.jobs_waiting
74
60
  rescue StandardError => e
75
- ::GRPC.logger.warn("Failed to get job count: #{e.message}")
76
- # Assume maximum load if we can't determine the actual count
61
+ Gruf.logger.warn("Failed to get job count: #{e.message}") if defined?(Gruf) && Gruf.respond_to?(:logger)
77
62
  @max_waiting_requests
78
63
  end
79
64
 
80
- # Send RESOURCE_EXHAUSTED status to client with error handling.
81
- #
82
- # @param an_rpc [Object] The RPC to send error response to
83
- # @return [void]
84
65
  def send_resource_exhausted_response(an_rpc)
85
- ::GRPC.logger.warn('no free worker threads currently') if ::GRPC.logger.respond_to?(:warn)
66
+ Gruf.logger.warn('no free worker threads currently') if defined?(Gruf) && Gruf.respond_to?(:logger)
86
67
 
87
68
  begin
88
- # Try calling send_status directly on the RPC object first (for test mocks)
89
69
  if an_rpc.respond_to?(:send_status)
90
70
  an_rpc.send_status(
91
71
  ::GRPC::Core::StatusCodes::RESOURCE_EXHAUSTED,
@@ -95,7 +75,6 @@ module Gruf
95
75
  return
96
76
  end
97
77
 
98
- # Create a new active call that knows that metadata hasn't been sent yet
99
78
  active_call = ::GRPC::ActiveCall.new(
100
79
  an_rpc.call,
101
80
  NOOP_PROC,
@@ -110,15 +89,13 @@ module Gruf
110
89
  RESOURCE_EXHAUSTED_MESSAGE,
111
90
  )
112
91
  rescue TypeError => e
113
- # Handle test scenario where an_rpc.call is a mock object
114
92
  raise unless e.message.include?('Core::Call')
115
93
 
116
- # In test environment, just log the response
117
94
  warn "RESOURCE_EXHAUSTED: #{RESOURCE_EXHAUSTED_MESSAGE}" if defined?(RSpec)
118
95
  end
119
96
  rescue StandardError => e
120
- if ::GRPC.logger.respond_to?(:error)
121
- ::GRPC.logger.error("Failed to send resource exhausted response: #{e.message}")
97
+ if defined?(Gruf) && Gruf.respond_to?(:logger)
98
+ Gruf.logger.error("Failed to send resource exhausted response: #{e.message}")
122
99
  else
123
100
  warn "Failed to send resource exhausted response: #{e.message}"
124
101
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Gruf
4
4
  module Queue
5
- VERSION = '0.1.1'
5
+ VERSION = '0.1.2'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gruf-queue
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ether Moon
@@ -139,6 +139,7 @@ files:
139
139
  - lib/gruf/queue/interceptors/connection_reset.rb
140
140
  - lib/gruf/queue/plugin.rb
141
141
  - lib/gruf/queue/pool.rb
142
+ - lib/gruf/queue/pool_enhancements.rb
142
143
  - lib/gruf/queue/queued_rpc_server.rb
143
144
  - lib/gruf/queue/server_factory.rb
144
145
  - lib/gruf/queue/version.rb