feat(runtime): unregister service revisions
Add a lifecycle-serialized unregister operation that stops a resident Actor before releasing its registered and compiled Component. Return the existing not-registered and unavailable errors without leaving a partially removed live revision, and cover Actor and registration count cleanup.
This commit is contained in:
@@ -390,6 +390,55 @@ impl Runtime {
|
||||
self.start(&key, init_config)
|
||||
}
|
||||
|
||||
/// Stops and removes one registered service revision.
|
||||
///
|
||||
/// Callers must switch any external deployment reference away from this
|
||||
/// revision before unregistering it.
|
||||
pub fn unregister(&self, key: &ServiceKey) -> Result<(), RuntimeError> {
|
||||
let _lifecycle = self
|
||||
.inner
|
||||
.lifecycle
|
||||
.lock()
|
||||
.map_err(|_| RuntimeError::LockPoisoned)?;
|
||||
|
||||
if !self
|
||||
.inner
|
||||
.services
|
||||
.lock()
|
||||
.map_err(|_| RuntimeError::LockPoisoned)?
|
||||
.contains_key(key)
|
||||
{
|
||||
return Err(RuntimeError::ServiceNotRegistered(key.clone()));
|
||||
}
|
||||
|
||||
let actor = self
|
||||
.inner
|
||||
.actors
|
||||
.lock()
|
||||
.map_err(|_| RuntimeError::LockPoisoned)?
|
||||
.get(key)
|
||||
.cloned();
|
||||
if let Some(actor) = actor {
|
||||
if actor.is_available() {
|
||||
actor.stop()?;
|
||||
} else if actor.is_alive() {
|
||||
return Err(RuntimeError::ActorUnavailable(key.clone()));
|
||||
}
|
||||
self.inner
|
||||
.actors
|
||||
.lock()
|
||||
.map_err(|_| RuntimeError::LockPoisoned)?
|
||||
.remove(key);
|
||||
}
|
||||
|
||||
self.inner
|
||||
.services
|
||||
.lock()
|
||||
.map_err(|_| RuntimeError::LockPoisoned)?
|
||||
.remove(key);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns counts without exposing internal Engine or Store state.
|
||||
pub fn stats(&self) -> Result<RuntimeStats, RuntimeError> {
|
||||
let registered_services = self
|
||||
|
||||
@@ -283,6 +283,23 @@ fn kv_capability_requires_a_backend_and_enforces_limits() {
|
||||
runtime.stop(&key).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unregister_stops_actor_and_releases_compiled_revision() {
|
||||
let runtime = Runtime::new(RuntimeConfig::default()).expect("runtime should start");
|
||||
let key = register_component(&runtime, "unregister", "echo_component.wasm", test_limits());
|
||||
runtime.start(&key, Vec::new()).unwrap();
|
||||
|
||||
runtime.unregister(&key).unwrap();
|
||||
|
||||
let stats = runtime.stats().unwrap();
|
||||
assert_eq!(stats.registered_services, 0);
|
||||
assert_eq!(stats.running_actors, 0);
|
||||
assert!(matches!(
|
||||
runtime.start(&key, Vec::new()),
|
||||
Err(RuntimeError::ServiceNotRegistered(missing)) if missing == key
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn registration_rejects_non_whitelisted_wasi_imports() {
|
||||
let runtime = Runtime::new(RuntimeConfig::default()).expect("runtime should start");
|
||||
|
||||
Reference in New Issue
Block a user