Skip to main content

RequestHandler

Struct RequestHandler 

Source
pub struct RequestHandler { /* private fields */ }
Expand description

The core protocol logic handler.

Orchestrates task lifecycle, event streaming, push notifications, and interceptor chains for all A2A methods.

RequestHandler is not generic — it stores the executor as Arc<dyn AgentExecutor>, enabling dynamic dispatch and simplifying the downstream API (dispatchers, builder, etc.).

§Store ownership

Stores are held as Arc<dyn TaskStore> / Arc<dyn PushConfigStore> rather than Box<dyn ...> so that they can be cheaply cloned into background tasks (e.g. the streaming push-delivery processor).

Implementations§

Source§

impl RequestHandler

Source

pub fn activated_extensions( &self, headers: &HashMap<String, String>, ) -> Vec<String>

Returns the activated extension set for a request: the intersection of the client’s A2A-Extensions declaration and the card’s declared extensions, in request order. HTTP dispatchers echo this back in the response A2A-Extensions header (official-SDK convention) so clients know which requested extensions the agent honored.

Source§

impl RequestHandler

Source

pub async fn active_queue_count(&self) -> usize

Number of event queues currently alive.

One queue exists per in-flight task and is destroyed when the task finishes, so under steady traffic this tracks concurrency rather than throughput. A value that climbs with cumulative request count — instead of settling — means queues are not being reclaimed.

Exposed for monitoring and for the sustained-load tests. The Metrics::on_queue_depth_change callback reports the same quantity as it changes; this is the pull-based counterpart, for a gauge scrape or a health page.

Source

pub async fn task_count(&self) -> A2aResult<u64>

Number of tasks currently held by the task store.

Delegates to count on the configured store.

§Errors

Returns whatever the store returned.

Source

pub async fn cancellation_token_count(&self) -> usize

Number of registered cancellation tokens.

One is registered per in-flight task and removed when it finishes, so like active_queue_count this should settle under steady traffic rather than climb. It has its own bound (max_cancellation_tokens), so a leak here eventually rejects new work rather than only consuming memory — which makes it worth watching directly.

Source

pub async fn task_store_health(&self) -> A2aResult<()>

Probes the task store, for readiness checks.

Answers the one question a readiness probe needs: can this replica reach the dependency it cannot serve a request without? A liveness probe deliberately cannot answer that — making liveness depend on a downstream turns that downstream’s outage into a restart loop across every replica, which is how a degraded service becomes an unavailable one.

Implemented as count, which every bundled store answers with a cheap query. It performs no write, so a store at its capacity limit still reports healthy — capacity is not the same question as reachability, and conflating them would drain traffic from a cluster that was merely full.

§Errors

Returns whatever the store returned. Callers exposing this over HTTP should surface metric_label rather than the message, which may name a host or a connection string.

Source§

impl RequestHandler

Source

pub async fn on_cancel_task( &self, params: CancelTaskParams, headers: Option<&HashMap<String, String>>, ) -> ServerResult<Task>

Handles CancelTask.

§Errors

Returns ServerError::TaskNotFound or ServerError::TaskNotCancelable.

Source§

impl RequestHandler

Source

pub async fn on_get_extended_agent_card( &self, headers: Option<&HashMap<String, String>>, ) -> ServerResult<AgentCard>

Handles GetExtendedAgentCard.

§Errors

Returns ServerError::Internal if no agent card is configured.

Source§

impl RequestHandler

Source

pub async fn on_get_task( &self, params: TaskQueryParams, headers: Option<&HashMap<String, String>>, ) -> ServerResult<Task>

Handles GetTask. Returns ServerError::TaskNotFound if missing.

§Errors

Returns ServerError::TaskNotFound if the task does not exist.

Source§

impl RequestHandler

Source

pub async fn on_list_tasks( &self, params: ListTasksParams, headers: Option<&HashMap<String, String>>, ) -> ServerResult<TaskListResponse>

Handles ListTasks.

§Errors

Returns a ServerError if the store query fails.

Source§

impl RequestHandler

Source

pub async fn on_resubscribe( &self, params: TaskIdParams, headers: Option<&HashMap<String, String>>, ) -> ServerResult<InMemoryQueueReader>

Handles SubscribeToTask.

§Errors

Returns ServerError::TaskNotFound if the task does not exist.

Source§

impl RequestHandler

Source

pub async fn on_send_message( &self, params: MessageSendParams, streaming: bool, headers: Option<&HashMap<String, String>>, ) -> ServerResult<SendMessageResult>

Handles SendMessage / SendStreamingMessage.

The optional headers map carries HTTP request headers for interceptor access-control decisions (e.g. Authorization).

§Errors

Returns ServerError if task creation or execution fails.

Source§

impl RequestHandler

Source

pub async fn on_set_push_config( &self, config: TaskPushNotificationConfig, headers: Option<&HashMap<String, String>>, ) -> ServerResult<TaskPushNotificationConfig>

Handles CreateTaskPushNotificationConfig.

§Errors

Returns ServerError::PushNotSupported if no push sender is configured.

Source

pub async fn on_get_push_config( &self, params: GetPushConfigParams, headers: Option<&HashMap<String, String>>, ) -> ServerResult<TaskPushNotificationConfig>

Handles GetTaskPushNotificationConfig.

§Errors

Returns ServerError::PushNotSupported if the agent card does not advertise push notifications, or ServerError::TaskNotFound if the requested configuration does not exist (spec §3.1.8).

Source

pub async fn on_list_push_configs( &self, task_id: &str, tenant: Option<&str>, headers: Option<&HashMap<String, String>>, ) -> ServerResult<Vec<TaskPushNotificationConfig>>

Handles ListTaskPushNotificationConfigs.

§Errors

Returns a ServerError if the store query fails.

Source

pub async fn on_delete_push_config( &self, params: DeletePushConfigParams, headers: Option<&HashMap<String, String>>, ) -> ServerResult<()>

Handles DeleteTaskPushNotificationConfig.

§Errors

Returns a ServerError if the delete operation fails.

Source§

impl RequestHandler

Source

pub async fn shutdown(&self) -> ShutdownReport

Initiates graceful shutdown of the handler.

This method:

  1. Cancels all in-flight tasks by signalling their cancellation tokens.
  2. Destroys all event queues, causing readers to see EOF.

After calling shutdown(), new requests will still be accepted but in-flight tasks will observe cancellation. The caller should stop accepting new connections after calling this method.

Returns a ShutdownReport describing whether the executor’s cleanup hook finished. This method does not wait for queues to drain, so queues_force_destroyed is always 0 — use shutdown_with_timeout when in-flight work should be given a chance to finish.

Source

pub async fn shutdown_with_timeout(&self, timeout: Duration) -> ShutdownReport

Initiates graceful shutdown, returning within timeout.

Cancels all in-flight tasks, waits for event queues to drain, and then runs the executor’s cleanup hook — all inside the one budget. This gives executors a chance to finish writing final events before the queues are torn down.

§timeout is the total, not a per-phase allowance

It was a per-phase allowance until 2026-08-19: the drain loop ran to now + timeout and then on_shutdown was given a fresh full timeout, so the call could take twice what the caller asked for. Measured on paused time with an undrainable queue and a cleanup hook that never returns, shutdown_with_timeout(30s) took 60s — exactly 2×.

That is not an academic overshoot. The number an operator puts here is the number they put in terminationGracePeriodSeconds, and a process that overruns it is SIGKILLed part-way through the cleanup this method exists to perform — truncating precisely the streams a graceful shutdown was protecting.

So the drain phase and the cleanup hook now share one deadline. If draining consumes the whole budget, cleanup is given what is left, which may be nothing; that is reported rather than papered over, because “your queues would not drain” and “your cleanup hook hung” are different problems and the caller can see which they had.

Returns a ShutdownReport: a non-zero queues_force_destroyed means the deadline passed with work still in flight, and executor_cleanup_completed == false means the executor’s cleanup hook was abandoned. Both are invisible from the outside otherwise, which is how a rollout can truncate every in-flight stream without anyone noticing.

Source§

impl RequestHandler

Source

pub fn tenant_resolver(&self) -> Option<&dyn TenantResolver>

Returns the tenant resolver, if configured.

Use this in dispatchers or middleware to resolve the tenant identity from a CallContext before processing a request.

Source

pub const fn tenant_config(&self) -> Option<&PerTenantConfig>

Returns the per-tenant limits this handler enforces, if any were set.

The handler applies them itself; this accessor is for inspection, and for handing the same configuration to RateLimitInterceptor::with_tenant_config, which is where rate_limit_rps is applied. See tenant_config.

Trait Implementations§

Source§

impl Debug for RequestHandler

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FutureExt for T

Source§

fn with_context(self, otel_cx: Context) -> WithContext<Self>

Attaches the provided Context to this type, returning a WithContext wrapper. Read more
Source§

fn with_current_context(self) -> WithContext<Self>

Attaches the current Context to this type, returning a WithContext wrapper. Read more
Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> IntoRequest<T> for T

Source§

fn into_request(self) -> Request<T>

Wrap the input message T in a tonic::Request
Source§

impl<L> LayerExt<L> for L

Source§

fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>
where L: Layer<S>,

Applies the layer to a service and wraps it in Layered.
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more