using concurrent::Futureusing afConcurrent::SynchronizedState** (Service) - Contribute functions to be executed on `Registry` shutdown. ** All functions need to be immutable, which essentially means they can only reference 'const' classes.** Example usage:** ** pre>** class AppModule {** @Contribute { serviceType=RegistryShutdown# }** static Void contributeRegistryShutdown(Configuration config, MyService myService) {** config["myShutdownFunc"] = |->| { myService.shutdown() }** }** }** <pre** ** If your shutdown method depends on other services still being available, add a constraint on their shutdown functions: ** ** shutdownFunc := |->| { myService.shutdown() }** config.set("myShutdownFunc", shutdownFunc).before("otherShutdownFunc")** ** IoC also defines a general use constraint placeholder named 'afIoc.shutdown'. ** ** Note that any Errs thrown by shutdown functions will be logged and then swallowed.** ** @uses Configuration of '|->| []'constmixin RegistryShutdown {internalabstract Void shutdown()}internalconstclass RegistryShutdownImpl : RegistryShutdown {privateconststatic Log log := Utils.getLog(RegistryShutdown#)privateconst OneShotLock lock := OneShotLock(IocMessages.registryShutdown)privateconst Str:|->| shutdownFuncs// Map needs to be keyed on Str so IoC can auto-generate keys in add()new make(Str:|->| shutdownFuncs){ shutdownFuncs.each |val, key| {try val.toImmutablecatchthrow NotImmutableErr(IocMessages.shutdownFuncNotImmutable(key))}this.shutdownFuncs = shutdownFuncs}override Void shutdown(){ lock.check lock.lock shutdownFuncs.each | |->| listener, Str id| {try{ listener.call}catch(Err e){ log.err(IocMessages.shutdownListenerError(id, e))}}}}