From: Alex Rousskov Date: Wed, 30 Mar 2011 18:07:38 +0000 (-0600) Subject: Instead of exiting, disable optional eCAP services that fail initialization. X-Git-Tag: take06~27^2~51 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=45d2da8b5a45802a06befbdcdaa22f6f3eba4738;p=thirdparty%2Fsquid.git Instead of exiting, disable optional eCAP services that fail initialization. Report all service initialization failures but mark optional services down instead of killing Squid by propagating the failure to the Squid core. An initialization failure of an optional (bypass=1) service should not lead to Squid quitting because, according to squid.conf, such a service may be replaced by other services (using adaptation sets) or simply ignored. Initialization failures of essential services still lead to fatal errors, but they are now reported better. Ecap services should indicate failures by throwing an exception. Squid reports exception details using std::exception::what() method if possible. --- diff --git a/src/adaptation/ecap/ServiceRep.cc b/src/adaptation/ecap/ServiceRep.cc index 1449c41373..b30e37f06a 100644 --- a/src/adaptation/ecap/ServiceRep.cc +++ b/src/adaptation/ecap/ServiceRep.cc @@ -99,17 +99,58 @@ Adaptation::Ecap::ServiceRep::finalize() Adaptation::Service::finalize(); theService = FindAdapterService(cfg().uri); if (theService) { - debugs(93,2, HERE << "configuring eCAP service: " << theService->uri()); - const ConfigRep cfgRep(dynamic_cast(cfg())); - theService->configure(cfgRep); - - debugs(93,DBG_IMPORTANT, "Starting eCAP service: " << theService->uri()); - theService->start(); + try { + tryConfigureAndStart(); + Must(up()); + } + catch (const std::exception &e) { // standardized exceptions + if (!handleFinalizeFailure(e.what())) + throw; // rethrow for upper layers to handle + } + catch (...) { // all other exceptions + if (!handleFinalizeFailure("unrecognized exception")) + throw; // rethrow for upper layers to handle + } + return; // success or handled exception } else { debugs(93,DBG_IMPORTANT, "WARNING: configured ecap_service was not loaded: " << cfg().uri); } } +/// attempts to configure and start eCAP service; the caller handles exceptions +void +Adaptation::Ecap::ServiceRep::tryConfigureAndStart() +{ + debugs(93,2, HERE << "configuring eCAP service: " << theService->uri()); + const ConfigRep cfgRep(dynamic_cast(cfg())); + theService->configure(cfgRep); + + debugs(93,DBG_IMPORTANT, "Starting eCAP service: " << theService->uri()); + theService->start(); +} + +/// handles failures while configuring or starting an eCAP service; +/// returns false if the error must be propagated to higher levels +bool +Adaptation::Ecap::ServiceRep::handleFinalizeFailure(const char *error) +{ + const bool salvage = cfg().bypass; + const int level = salvage ? DBG_IMPORTANT : DBG_CRITICAL; + const char *kind = salvage ? "optional" : "essential"; + debugs(93, level, "ERROR: failed to start " << kind << " eCAP service: " << + cfg().uri << ":\n" << error); + + if (!salvage) + return false; // we cannot handle the problem; the caller may escalate + + // make up() false, preventing new adaptation requests and enabling bypass + theService.reset(); + debugs(93, level, "WARNING: " << kind << " eCAP service is " << + "down after initialization failure: " << cfg().uri); + + return true; // tell the caller to ignore the problem because we handled it +} + bool Adaptation::Ecap::ServiceRep::probed() const { return true; // we "probe" the adapter in finalize(). diff --git a/src/adaptation/ecap/ServiceRep.h b/src/adaptation/ecap/ServiceRep.h index 8e1818f0f5..b21179b97b 100644 --- a/src/adaptation/ecap/ServiceRep.h +++ b/src/adaptation/ecap/ServiceRep.h @@ -39,6 +39,10 @@ public: virtual void detach(); virtual bool detached() const; +protected: + void tryConfigureAndStart(); + bool handleFinalizeFailure(const char *error); + private: AdapterService theService; // the actual adaptation service we represent bool isDetached;