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
impl HotReloadAgentCardHandler
Sourcepub fn update(&self, card: AgentCard)
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.
Sourcepub fn reload_from_file(&self, path: &Path) -> ServerResult<()>
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.
Sourcepub fn reload_from_json(&self, json: &str) -> ServerResult<()>
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.
Sourcepub fn spawn_poll_watcher(
&self,
path: &Path,
interval: Duration,
) -> JoinHandle<()> ⓘ
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).
Sourcepub fn spawn_signal_watcher(&self, path: &Path) -> JoinHandle<()> ⓘ
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 Clone for HotReloadAgentCardHandler
impl Clone for HotReloadAgentCardHandler
Source§fn clone(&self) -> HotReloadAgentCardHandler
fn clone(&self) -> HotReloadAgentCardHandler
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreAuto Trait Implementations§
impl Freeze for HotReloadAgentCardHandler
impl RefUnwindSafe for HotReloadAgentCardHandler
impl Send for HotReloadAgentCardHandler
impl Sync for HotReloadAgentCardHandler
impl Unpin for HotReloadAgentCardHandler
impl UnsafeUnpin for HotReloadAgentCardHandler
impl UnwindSafe for HotReloadAgentCardHandler
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> FutureExt for T
impl<T> FutureExt for T
Source§fn with_context(self, otel_cx: Context) -> WithContext<Self> ⓘ
fn with_context(self, otel_cx: Context) -> WithContext<Self> ⓘ
Source§fn with_current_context(self) -> WithContext<Self> ⓘ
fn with_current_context(self) -> WithContext<Self> ⓘ
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
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 moreSource§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request