Skip to main content

HotReloadAgentCardHandler

Struct HotReloadAgentCardHandler 

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

An agent card handler that supports hot-reloading.

The current AgentCard is stored behind an Arc<RwLock<_>> so that it can be atomically swapped while the server continues to serve requests.

This type implements AgentCardProducer, so it can be plugged directly into a DynamicAgentCardHandler for full HTTP caching support.

Implementations§

Source§

impl HotReloadAgentCardHandler

Source

pub fn new(card: AgentCard) -> Self

Creates a new handler with the given initial AgentCard.

Source

pub fn current(&self) -> AgentCard

Returns a snapshot of the current AgentCard.

This acquires a short-lived read lock and clones the card.

A poisoned lock is recovered from rather than propagated — see update.

Source

pub fn update(&self, card: AgentCard)

Replaces the current agent card with card.

All subsequent requests will see the new card immediately.

§A poisoned lock is recovered from, not propagated

Both accessors used to expect on the lock, so one panic anywhere under the write lock turned every subsequent agent-card request into a panic — on the request path, in a handler whose whole purpose is to answer GetAgentCard. In a release build that is worse still: this workspace sets panic = "abort", so the second panic is a process abort rather than one failed request.

Recovery is correct here, not merely convenient. The only write is this whole-value assignment of an already-constructed AgentCard, so there is no state in which the guarded value is half-updated for a later reader to observe. The same reasoning the rest of this workspace applies to its std mutexes.

Source

pub fn reload_from_file(&self, path: &Path) -> ServerResult<()>

Reloads the agent card from a JSON file at path.

The file is read synchronously (agent card files are expected to be small). On success the internal card is replaced atomically.

§Errors

Returns ServerError::Internal if the file cannot be read or parsed.

Source

pub fn reload_from_json(&self, json: &str) -> ServerResult<()>

Reloads the agent card from a JSON string.

On success the internal card is replaced atomically.

§Errors

Returns ServerError::Serialization if json is not valid agent card JSON.

Source

pub fn spawn_poll_watcher( &self, path: &Path, interval: Duration, ) -> JoinHandle<()>

Spawns a background task that periodically checks whether the file at path has been modified and reloads the agent card when it has.

The watcher compares the file’s modification time on each tick and only re-reads the file when the timestamp changes. This is cross-platform and requires no OS-specific file notification APIs.

Returns a tokio::task::JoinHandle that can be used to abort the watcher (via JoinHandle::abort).

Source

pub fn spawn_signal_watcher(&self, path: &Path) -> JoinHandle<()>

Spawns a background task that reloads the agent card from path whenever the process receives SIGHUP.

This is the traditional Unix mechanism for configuration reload and integrates well with process managers (systemd, supervisord, etc.).

Returns a tokio::task::JoinHandle that can be used to abort the watcher (via JoinHandle::abort).

If the handler cannot be registered for an ordinary I/O reason, the watcher logs a warning and exits; reload-on-SIGHUP is then unavailable, and reload_from_file and spawn_poll_watcher still work.

§Panics

Panics here, at this call, if the current Tokio runtime has no signal driver — there is no signal driver running, must be called from the context of Tokio runtime. That is what a runtime built by hand without enable_all() (or at least enable_io()) gives you; the #[tokio::main] default has it.

Registration used to happen inside the spawned task, which made the same panic much worse. It fired after this function had already returned a handle, so a caller had no way to see it coming and nothing to catch — and this workspace builds release with panic = "abort", so what a developer would meet as a failing startup in the first case is a process abort at an arbitrary later moment in the second. Registering synchronously does not remove the panic; it moves it to the caller’s own startup path, where it is deterministic and where this paragraph is about the function it is attached to.

Trait Implementations§

Source§

impl AgentCardProducer for HotReloadAgentCardHandler

Source§

fn produce<'a>( &'a self, ) -> Pin<Box<dyn Future<Output = A2aResult<AgentCard>> + Send + 'a>>

Produces an AgentCard for the current request. Read more
Source§

impl Clone for HotReloadAgentCardHandler

Source§

fn clone(&self) -> HotReloadAgentCardHandler

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for HotReloadAgentCardHandler

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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FromRef<T> for T
where T: Clone,

Source§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
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> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
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