a2a-ruby 1.0.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 +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +137 -0
- data/.simplecov +46 -0
- data/.yardopts +10 -0
- data/CHANGELOG.md +33 -0
- data/CODE_OF_CONDUCT.md +128 -0
- data/CONTRIBUTING.md +165 -0
- data/Gemfile +43 -0
- data/Guardfile +34 -0
- data/LICENSE.txt +21 -0
- data/PUBLISHING_CHECKLIST.md +214 -0
- data/README.md +171 -0
- data/Rakefile +165 -0
- data/docs/agent_execution.md +309 -0
- data/docs/api_reference.md +792 -0
- data/docs/configuration.md +780 -0
- data/docs/events.md +475 -0
- data/docs/getting_started.md +668 -0
- data/docs/integration.md +262 -0
- data/docs/server_apps.md +621 -0
- data/docs/troubleshooting.md +765 -0
- data/lib/a2a/client/api_methods.rb +263 -0
- data/lib/a2a/client/auth/api_key.rb +161 -0
- data/lib/a2a/client/auth/interceptor.rb +288 -0
- data/lib/a2a/client/auth/jwt.rb +189 -0
- data/lib/a2a/client/auth/oauth2.rb +146 -0
- data/lib/a2a/client/auth.rb +137 -0
- data/lib/a2a/client/base.rb +316 -0
- data/lib/a2a/client/config.rb +210 -0
- data/lib/a2a/client/connection_pool.rb +233 -0
- data/lib/a2a/client/http_client.rb +524 -0
- data/lib/a2a/client/json_rpc_handler.rb +136 -0
- data/lib/a2a/client/middleware/circuit_breaker_interceptor.rb +245 -0
- data/lib/a2a/client/middleware/logging_interceptor.rb +371 -0
- data/lib/a2a/client/middleware/rate_limit_interceptor.rb +142 -0
- data/lib/a2a/client/middleware/retry_interceptor.rb +161 -0
- data/lib/a2a/client/middleware.rb +116 -0
- data/lib/a2a/client/performance_tracker.rb +60 -0
- data/lib/a2a/configuration/defaults.rb +34 -0
- data/lib/a2a/configuration/environment_loader.rb +76 -0
- data/lib/a2a/configuration/file_loader.rb +115 -0
- data/lib/a2a/configuration/inheritance.rb +101 -0
- data/lib/a2a/configuration/validator.rb +180 -0
- data/lib/a2a/configuration.rb +201 -0
- data/lib/a2a/errors.rb +291 -0
- data/lib/a2a/modules.rb +50 -0
- data/lib/a2a/monitoring/alerting.rb +490 -0
- data/lib/a2a/monitoring/distributed_tracing.rb +398 -0
- data/lib/a2a/monitoring/health_endpoints.rb +204 -0
- data/lib/a2a/monitoring/metrics_collector.rb +438 -0
- data/lib/a2a/monitoring.rb +463 -0
- data/lib/a2a/plugin.rb +358 -0
- data/lib/a2a/plugin_manager.rb +159 -0
- data/lib/a2a/plugins/example_auth.rb +81 -0
- data/lib/a2a/plugins/example_middleware.rb +118 -0
- data/lib/a2a/plugins/example_transport.rb +76 -0
- data/lib/a2a/protocol/agent_card.rb +8 -0
- data/lib/a2a/protocol/agent_card_server.rb +584 -0
- data/lib/a2a/protocol/capability.rb +496 -0
- data/lib/a2a/protocol/json_rpc.rb +254 -0
- data/lib/a2a/protocol/message.rb +8 -0
- data/lib/a2a/protocol/task.rb +8 -0
- data/lib/a2a/rails/a2a_controller.rb +258 -0
- data/lib/a2a/rails/controller_helpers.rb +499 -0
- data/lib/a2a/rails/engine.rb +167 -0
- data/lib/a2a/rails/generators/agent_generator.rb +311 -0
- data/lib/a2a/rails/generators/install_generator.rb +209 -0
- data/lib/a2a/rails/generators/migration_generator.rb +232 -0
- data/lib/a2a/rails/generators/templates/add_a2a_indexes.rb +57 -0
- data/lib/a2a/rails/generators/templates/agent_controller.rb +122 -0
- data/lib/a2a/rails/generators/templates/agent_controller_spec.rb +160 -0
- data/lib/a2a/rails/generators/templates/agent_readme.md +200 -0
- data/lib/a2a/rails/generators/templates/create_a2a_push_notification_configs.rb +68 -0
- data/lib/a2a/rails/generators/templates/create_a2a_tasks.rb +83 -0
- data/lib/a2a/rails/generators/templates/example_agent_controller.rb +228 -0
- data/lib/a2a/rails/generators/templates/initializer.rb +108 -0
- data/lib/a2a/rails/generators/templates/push_notification_config_model.rb +228 -0
- data/lib/a2a/rails/generators/templates/task_model.rb +200 -0
- data/lib/a2a/rails/tasks/a2a.rake +228 -0
- data/lib/a2a/server/a2a_methods.rb +520 -0
- data/lib/a2a/server/agent.rb +537 -0
- data/lib/a2a/server/agent_execution/agent_executor.rb +279 -0
- data/lib/a2a/server/agent_execution/request_context.rb +219 -0
- data/lib/a2a/server/apps/rack_app.rb +311 -0
- data/lib/a2a/server/apps/sinatra_app.rb +261 -0
- data/lib/a2a/server/default_request_handler.rb +350 -0
- data/lib/a2a/server/events/event_consumer.rb +116 -0
- data/lib/a2a/server/events/event_queue.rb +226 -0
- data/lib/a2a/server/example_agent.rb +248 -0
- data/lib/a2a/server/handler.rb +281 -0
- data/lib/a2a/server/middleware/authentication_middleware.rb +212 -0
- data/lib/a2a/server/middleware/cors_middleware.rb +171 -0
- data/lib/a2a/server/middleware/logging_middleware.rb +362 -0
- data/lib/a2a/server/middleware/rate_limit_middleware.rb +382 -0
- data/lib/a2a/server/middleware.rb +213 -0
- data/lib/a2a/server/push_notification_manager.rb +327 -0
- data/lib/a2a/server/request_handler.rb +136 -0
- data/lib/a2a/server/storage/base.rb +141 -0
- data/lib/a2a/server/storage/database.rb +266 -0
- data/lib/a2a/server/storage/memory.rb +274 -0
- data/lib/a2a/server/storage/redis.rb +320 -0
- data/lib/a2a/server/storage.rb +38 -0
- data/lib/a2a/server/task_manager.rb +534 -0
- data/lib/a2a/transport/grpc.rb +481 -0
- data/lib/a2a/transport/http.rb +415 -0
- data/lib/a2a/transport/sse.rb +499 -0
- data/lib/a2a/types/agent_card.rb +540 -0
- data/lib/a2a/types/artifact.rb +99 -0
- data/lib/a2a/types/base_model.rb +223 -0
- data/lib/a2a/types/events.rb +117 -0
- data/lib/a2a/types/message.rb +106 -0
- data/lib/a2a/types/part.rb +288 -0
- data/lib/a2a/types/push_notification.rb +139 -0
- data/lib/a2a/types/security.rb +167 -0
- data/lib/a2a/types/task.rb +154 -0
- data/lib/a2a/types.rb +88 -0
- data/lib/a2a/utils/helpers.rb +245 -0
- data/lib/a2a/utils/message_buffer.rb +278 -0
- data/lib/a2a/utils/performance.rb +247 -0
- data/lib/a2a/utils/rails_detection.rb +97 -0
- data/lib/a2a/utils/structured_logger.rb +306 -0
- data/lib/a2a/utils/time_helpers.rb +167 -0
- data/lib/a2a/utils/validation.rb +8 -0
- data/lib/a2a/version.rb +6 -0
- data/lib/a2a-rails.rb +58 -0
- data/lib/a2a.rb +198 -0
- metadata +437 -0
@@ -0,0 +1,233 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "monitor"
|
4
|
+
|
5
|
+
module A2A
|
6
|
+
module Client
|
7
|
+
##
|
8
|
+
# Connection pool manager for HTTP clients
|
9
|
+
#
|
10
|
+
# Manages a pool of HTTP connections to improve performance by reusing
|
11
|
+
# connections and avoiding the overhead of establishing new connections
|
12
|
+
# for each request.
|
13
|
+
#
|
14
|
+
class ConnectionPool
|
15
|
+
include MonitorMixin
|
16
|
+
|
17
|
+
# Default pool configuration
|
18
|
+
DEFAULT_POOL_SIZE = 5
|
19
|
+
DEFAULT_TIMEOUT = 5
|
20
|
+
DEFAULT_IDLE_TIMEOUT = 30
|
21
|
+
|
22
|
+
attr_reader :size, :timeout, :idle_timeout, :created, :checked_out
|
23
|
+
|
24
|
+
##
|
25
|
+
# Initialize a new connection pool
|
26
|
+
#
|
27
|
+
# @param size [Integer] Maximum number of connections in the pool
|
28
|
+
# @param timeout [Integer] Timeout for checking out a connection
|
29
|
+
# @param idle_timeout [Integer] Timeout for idle connections
|
30
|
+
# @yield Block that creates a new connection
|
31
|
+
def initialize(size: DEFAULT_POOL_SIZE, timeout: DEFAULT_TIMEOUT, idle_timeout: DEFAULT_IDLE_TIMEOUT, &block)
|
32
|
+
super()
|
33
|
+
|
34
|
+
@size = size
|
35
|
+
@timeout = timeout
|
36
|
+
@idle_timeout = idle_timeout
|
37
|
+
@connection_factory = block
|
38
|
+
@pool = []
|
39
|
+
@checked_out = []
|
40
|
+
@created = 0
|
41
|
+
@last_cleanup = Time.now
|
42
|
+
end
|
43
|
+
|
44
|
+
##
|
45
|
+
# Check out a connection from the pool
|
46
|
+
#
|
47
|
+
# @return [Object] A connection from the pool
|
48
|
+
# @raise [TimeoutError] If no connection is available within timeout
|
49
|
+
def checkout
|
50
|
+
synchronize do
|
51
|
+
# Try to get an existing connection
|
52
|
+
connection = @pool.pop
|
53
|
+
|
54
|
+
# Create a new connection if pool is empty and we haven't reached the limit
|
55
|
+
connection = create_connection if connection.nil? && @created < @size
|
56
|
+
|
57
|
+
# Wait for a connection to become available
|
58
|
+
if connection.nil?
|
59
|
+
deadline = Time.now + @timeout
|
60
|
+
|
61
|
+
while connection.nil? && Time.now < deadline
|
62
|
+
ns_wait(0.1) # Wait 100ms
|
63
|
+
connection = @pool.pop
|
64
|
+
end
|
65
|
+
|
66
|
+
raise TimeoutError, "Could not checkout connection within #{@timeout}s" if connection.nil?
|
67
|
+
end
|
68
|
+
|
69
|
+
# Mark connection as checked out
|
70
|
+
@checked_out << connection
|
71
|
+
|
72
|
+
# Cleanup idle connections periodically
|
73
|
+
cleanup_idle_connections if should_cleanup?
|
74
|
+
|
75
|
+
connection
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
##
|
80
|
+
# Check in a connection to the pool
|
81
|
+
#
|
82
|
+
# @param connection [Object] The connection to return to the pool
|
83
|
+
def checkin(connection)
|
84
|
+
synchronize do
|
85
|
+
@checked_out.delete(connection)
|
86
|
+
|
87
|
+
# Add connection back to pool if it's still valid
|
88
|
+
if valid_connection?(connection)
|
89
|
+
connection.instance_variable_set(:@last_used, Time.now)
|
90
|
+
@pool.push(connection)
|
91
|
+
else
|
92
|
+
# Connection is invalid, create a new one to replace it
|
93
|
+
@created -= 1
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
##
|
99
|
+
# Execute a block with a connection from the pool
|
100
|
+
#
|
101
|
+
# @yield [connection] Block to execute with the connection
|
102
|
+
# @return [Object] Result of the block
|
103
|
+
def with_connection
|
104
|
+
connection = checkout
|
105
|
+
begin
|
106
|
+
yield connection
|
107
|
+
ensure
|
108
|
+
checkin(connection)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
##
|
113
|
+
# Get pool statistics
|
114
|
+
#
|
115
|
+
# @return [Hash] Pool statistics
|
116
|
+
def stats
|
117
|
+
synchronize do
|
118
|
+
{
|
119
|
+
size: @size,
|
120
|
+
created: @created,
|
121
|
+
available: @pool.size,
|
122
|
+
checked_out: @checked_out.size,
|
123
|
+
idle_timeout: @idle_timeout,
|
124
|
+
timeout: @timeout
|
125
|
+
}
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
##
|
130
|
+
# Close all connections in the pool
|
131
|
+
#
|
132
|
+
def close_all
|
133
|
+
synchronize do
|
134
|
+
(@pool + @checked_out).each do |connection|
|
135
|
+
close_connection(connection)
|
136
|
+
end
|
137
|
+
|
138
|
+
@pool.clear
|
139
|
+
@checked_out.clear
|
140
|
+
@created = 0
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
##
|
145
|
+
# Flush idle connections from the pool
|
146
|
+
#
|
147
|
+
def flush_idle!
|
148
|
+
synchronize do
|
149
|
+
cleanup_idle_connections
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
private
|
154
|
+
|
155
|
+
##
|
156
|
+
# Create a new connection
|
157
|
+
#
|
158
|
+
# @return [Object] New connection
|
159
|
+
def create_connection
|
160
|
+
return nil unless @connection_factory
|
161
|
+
|
162
|
+
connection = @connection_factory.call
|
163
|
+
connection.instance_variable_set(:@created_at, Time.now)
|
164
|
+
connection.instance_variable_set(:@last_used, Time.now)
|
165
|
+
@created += 1
|
166
|
+
|
167
|
+
connection
|
168
|
+
end
|
169
|
+
|
170
|
+
##
|
171
|
+
# Check if a connection is valid
|
172
|
+
#
|
173
|
+
# @param connection [Object] Connection to validate
|
174
|
+
# @return [Boolean] True if connection is valid
|
175
|
+
def valid_connection?(connection)
|
176
|
+
return false unless connection
|
177
|
+
|
178
|
+
# Check if connection responds to basic methods
|
179
|
+
return false unless connection.respond_to?(:get) || connection.respond_to?(:request)
|
180
|
+
|
181
|
+
# Check if connection is not too old
|
182
|
+
created_at = connection.instance_variable_get(:@created_at)
|
183
|
+
return false if created_at && (Time.now - created_at) > (@idle_timeout * 10)
|
184
|
+
|
185
|
+
true
|
186
|
+
rescue StandardError
|
187
|
+
false
|
188
|
+
end
|
189
|
+
|
190
|
+
##
|
191
|
+
# Close a connection
|
192
|
+
#
|
193
|
+
# @param connection [Object] Connection to close
|
194
|
+
def close_connection(connection)
|
195
|
+
connection.close if connection.respond_to?(:close)
|
196
|
+
rescue StandardError
|
197
|
+
# Ignore errors when closing connections
|
198
|
+
end
|
199
|
+
|
200
|
+
##
|
201
|
+
# Check if we should run cleanup
|
202
|
+
#
|
203
|
+
# @return [Boolean] True if cleanup should run
|
204
|
+
def should_cleanup?
|
205
|
+
Time.now - @last_cleanup > 60 # Cleanup every minute
|
206
|
+
end
|
207
|
+
|
208
|
+
##
|
209
|
+
# Clean up idle connections
|
210
|
+
#
|
211
|
+
def cleanup_idle_connections
|
212
|
+
@last_cleanup = Time.now
|
213
|
+
cutoff_time = Time.now - @idle_timeout
|
214
|
+
|
215
|
+
@pool.reject! do |connection|
|
216
|
+
last_used = connection.instance_variable_get(:@last_used)
|
217
|
+
if last_used && last_used < cutoff_time
|
218
|
+
close_connection(connection)
|
219
|
+
@created -= 1
|
220
|
+
true
|
221
|
+
else
|
222
|
+
false
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
##
|
229
|
+
# Timeout error for connection pool operations
|
230
|
+
#
|
231
|
+
class TimeoutError < StandardError; end
|
232
|
+
end
|
233
|
+
end
|