pub struct ServerHandle { /* private fields */ }Expand description
The handle to a server being served, which is what owns it on behalf of its caller, and derefs to it.
A server ends by being stopped, see Server::stop_async, which deletes its devices, by its
owner or by a client through the Kill command of its admin device, and is waited for
by its owner, see Server::wait. A server is always stopped: dropping the handle of a
server that was not only stops its backend, with no other side effect, see Drop.
Implementations§
Methods from Deref<Target = Server>§
Sourcepub fn name(&self) -> &str
pub fn name(&self) -> &str
The exe/inst name of that server, under which it is registered in the database.
Sourcepub fn admin_dev_name(&self) -> &str
pub fn admin_dev_name(&self) -> &str
The name of the admin device of that server, dserver/exe/inst.
Sourcepub fn database(&self) -> &DatabaseProxy
pub fn database(&self) -> &DatabaseProxy
The database that server is registered in.
Sourcepub fn backend(&self) -> Option<Arc<dyn BackendServer>>
pub fn backend(&self) -> Option<Arc<dyn BackendServer>>
The backend serving the devices of that server, None once it is not served
anymore, see ServerHandle.
Sourcepub fn add_class<M: Model>(&self, def: ClassDef<M>) -> Result<Arc<Class<M>>>
pub fn add_class<M: Model>(&self, def: ClassDef<M>) -> Result<Arc<Class<M>>>
Register a new class in this server, from its definition.
Sourcepub fn get_class<M: Model>(&self, name: &str) -> Option<Arc<Class<M>>>
pub fn get_class<M: Model>(&self, name: &str) -> Option<Arc<Class<M>>>
Get a class of this server from its name, if it is one of that model.
Sourcepub fn add_dev(&self, class: &str, name: &str) -> Result<()>
pub fn add_dev(&self, class: &str, name: &str) -> Result<()>
Add a device to this server, as an instance of the class of that name, which is how
the devices listed by the database are added, the database giving the class of each
by its name. See Class::add_dev for the typed form.
The device is only registered: it is initialized, served and exported by the next
Self::sync_async.
Sourcepub fn remove_dev(&self, name: &str) -> bool
pub fn remove_dev(&self, name: &str) -> bool
Remove the device of that name from this server, giving back whether it had one.
Its name is free again right away, but the device itself is only unexported, no
longer served and deleted by the next Self::sync_async. A device removed before any
synchronization reached it is simply dropped.
Sourcepub async fn sync_async(&self) -> Result<()>
pub async fn sync_async(&self) -> Result<()>
Apply what was done to the devices of this server since the last synchronization: the devices removed are unexported, no longer served and deleted, then the devices added are initialized, served and exported, which is what makes them reachable.
The devices added are initialized one after the other, class by class in the order the classes were made, and in the order they were added within a class. A device whose initialization adds devices has them initialized by this same synchronization, which is how the admin device boots a server. Each device is then served and exported on its own, which is what a Tango server always tells the database.
A device whose initialization failed is still served and exported, in FAULT, so that a client can ask it what went wrong. A device that could not be served or exported is retried by the next synchronization, and the first such error is given back once every other device is done.
Synchronizations never interleave: one waits for the one running to be done, so that everything done before calling it is applied once it returns. This is also why an init function must never call it, since it would wait for itself.
Sourcepub fn sync(&self) -> Result<()>
pub fn sync(&self) -> Result<()>
The blocking form of Self::sync_async, which must therefore never run on the
executor of a backend, in an asynchronous handler in particular.
Sourcepub fn class_names(&self) -> Vec<Arc<str>>
pub fn class_names(&self) -> Vec<Arc<str>>
The names of every class of this server, in the order they were made, the admin one first.
Sourcepub fn dev_names(&self) -> Vec<Arc<str>>
pub fn dev_names(&self) -> Vec<Arc<str>>
The names of every device of this server, class by class in the order of
Self::class_names, and by name within a class.
Sourcepub fn get_dev<M: Model>(&self, name: &str) -> Option<Arc<Dev<M>>>
pub fn get_dev<M: Model>(&self, name: &str) -> Option<Arc<Dev<M>>>
Get a device of this server from its name, if its class is one of that model.
Sourcepub async fn stop_async(&self) -> Result<()>
pub async fn stop_async(&self) -> Result<()>
Stop this server, which is only ever done once: it is unexported as a whole, so
that clients stop finding it, then its backend is stopped, the requests in flight
still being answered, and its devices are deleted, see Self::wait for what waits
for the backend to be through. No synchronization runs after this, the devices
still waiting for one never being served.
The devices are deleted one after the other, the classes in the reverse of their
order, the admin device last, each once the requests still running on it are
through, see Dev::is_withdrawn: a request that never ends therefore keeps this
from ever returning. This is also why a request handler must never call it, since
it would wait for itself; the Kill command of the admin device stops its server
from the pool instead.
The backend is stopped and the devices deleted even if the server could not be unexported, and the first error met is given back.
Sourcepub fn stop(&self) -> Result<()>
pub fn stop(&self) -> Result<()>
The blocking form of Self::stop_async, which must therefore never run on the
executor of a backend, in an asynchronous handler in particular.
Sourcepub async fn wait_async(&self)
pub async fn wait_async(&self)
Wait for this server to be stopped, see Self::stop_async, which is what the
thread running a server spends its life in: for its backend to be through with
every request, and for its devices to be deleted. A server that is not served
anymore, see ServerHandle, is not waited for.
The backend is waited for first, which is only through once stopped, see
BackendServer::wait, then the stop itself, which deletes the devices under the
lock of the synchronizations. This waits for every request in flight, and must
therefore never be called from a request handler, which would wait for itself.
Sourcepub fn wait(&self)
pub fn wait(&self)
The blocking form of Self::wait_async, which must therefore never run on the
executor of a backend, in an asynchronous handler in particular. See
Self::wait_timeout for a wait that gives up.
Sourcepub fn wait_timeout(&self, timeout: Duration) -> Result<()>
pub fn wait_timeout(&self, timeout: Duration) -> Result<()>
Wait for this server to be stopped, see Self::wait_async, giving up with
ErrorKind::TimedOut if the backend is still answering requests once the timeout
has run out, which a request that never ends makes it, or a server never stopped.
The timeout only bounds the backend: once it is through, the deletion of the devices is waited for, however long that takes.
Trait Implementations§
Source§impl Debug for ServerHandle
impl Debug for ServerHandle
Source§impl Deref for ServerHandle
impl Deref for ServerHandle
Source§impl Drop for ServerHandle
impl Drop for ServerHandle
Source§fn drop(&mut self)
fn drop(&mut self)
Stop the backend and end the subscriptions, with no other side effect: a server
that was not stopped, see Server::stop_async, is not unexported, and its models are
not deleted. The requests in flight are not waited for, and everything of the server
is let go of once they end, see BackendServer, a request still holding it for
the time of a Server::sync_async or a Server::stop_async it runs.