refactor: Drop modules on failure

If a module error occur, just stop the failing
module and let the application keep running.
This commit is contained in:
Michael Carlberg 2016-10-11 07:54:03 +02:00
parent 69f648c513
commit 89d645539c
3 changed files with 85 additions and 45 deletions

View File

@ -67,6 +67,7 @@ class controller {
for (auto&& block : m_modules) { for (auto&& block : m_modules) {
for (auto&& module : block.second) { for (auto&& module : block.second) {
module->on_update.disconnect(this, &controller::on_module_update); module->on_update.disconnect(this, &controller::on_module_update);
module->on_stop.disconnect(this, &controller::on_module_stop);
module->stop(); module->stop();
} }
} }
@ -95,6 +96,7 @@ class controller {
for (auto&& block : m_modules) { for (auto&& block : m_modules) {
for (auto&& module : block.second) { for (auto&& module : block.second) {
module->on_update.disconnect(this, &controller::on_module_update); module->on_update.disconnect(this, &controller::on_module_update);
module->on_stop.disconnect(this, &controller::on_module_stop);
module->stop(); module->stop();
} }
} }
@ -203,7 +205,13 @@ class controller {
for (auto&& block : m_modules) { for (auto&& block : m_modules) {
for (auto&& module : block.second) { for (auto&& module : block.second) {
module->on_update.connect(this, &controller::on_module_update); module->on_update.connect(this, &controller::on_module_update);
module->start(); module->on_stop.connect(this, &controller::on_module_stop);
try {
module->start();
} catch (const application_error& err) {
m_log.err("Failed to start '%s' (reason: %s)", module->name(), err.what());
}
} }
} }
@ -463,6 +471,18 @@ class controller {
m_bar->parse(contents); m_bar->parse(contents);
} }
void on_module_stop(string module_name) {
for (auto&& block : m_modules) {
for (auto&& module : block.second) {
if (module->running())
return;
}
}
m_log.warn("No running modules, raising SIGTERM");
kill(getpid(), SIGTERM);
}
void on_module_click(string input) { void on_module_click(string input) {
if (!m_mutex.try_lock()) if (!m_mutex.try_lock())
return; return;

View File

@ -148,6 +148,7 @@ namespace modules {
virtual ~module_interface() {} virtual ~module_interface() {}
virtual string name() const = 0; virtual string name() const = 0;
virtual bool running() const = 0;
virtual void setup() = 0; virtual void setup() = 0;
virtual void start() = 0; virtual void start() = 0;
@ -159,6 +160,7 @@ namespace modules {
virtual bool receive_events() const = 0; virtual bool receive_events() const = 0;
delegate::Signal1<string> on_update; delegate::Signal1<string> on_update;
delegate::Signal1<string> on_stop;
}; };
// }}} // }}}
@ -195,17 +197,23 @@ namespace modules {
return m_name; return m_name;
} }
bool running() const {
return enabled();
}
void setup() { void setup() {
m_log.trace("%s: Setup", name()); m_log.trace("%s: Setup", name());
CAST_MODULE(Impl)->setup(); CAST_MODULE(Impl)->setup();
} }
void stop() { void stop() {
// std::lock_guard<concurrency::SpinLock> lck(this->broadcast_lock); if (!enabled())
// std::lock_guard<threading_util::spin_lock> lck(this->update_lock); return;
m_log.trace("%s: Stop", name()); m_log.trace("%s: Stop", name());
enable(false); enable(false);
wakeup(); wakeup();
if (!on_stop.empty())
on_stop.emit(name());
} }
void refresh() { void refresh() {
@ -265,8 +273,6 @@ namespace modules {
} }
string get_output() { string get_output() {
// std::lock_guard<concurrency::SpinLock> lck(this->output_lock);
if (!enabled()) { if (!enabled()) {
m_log.trace("%s: Module is disabled", name()); m_log.trace("%s: Module is disabled", name());
return ""; return "";
@ -332,7 +338,7 @@ namespace modules {
void start() { void start() {
CAST_MODULE(Impl)->setup(); CAST_MODULE(Impl)->setup();
CAST_MODULE(Impl)->enable(true); CAST_MODULE(Impl)->enable(true);
CAST_MODULE(Impl)->m_threads.emplace_back(thread(&static_module::broadcast, this)); CAST_MODULE(Impl)->broadcast();
} }
bool build(builder*, string) { bool build(builder*, string) {
@ -359,15 +365,21 @@ namespace modules {
interval_t m_interval = 1s; interval_t m_interval = 1s;
void runner() { void runner() {
CAST_MODULE(Impl)->setup(); try {
CAST_MODULE(Impl)->setup();
while (CONST_CAST_MODULE(Impl).enabled()) { while (CONST_CAST_MODULE(Impl).enabled()) {
{ {
std::lock_guard<threading_util::spin_lock> lck(this->update_lock); std::lock_guard<threading_util::spin_lock> lck(this->update_lock);
if (CAST_MODULE(Impl)->update()) if (CAST_MODULE(Impl)->update())
CAST_MODULE(Impl)->broadcast(); CAST_MODULE(Impl)->broadcast();
}
CAST_MODULE(Impl)->sleep(m_interval);
} }
CAST_MODULE(Impl)->sleep(m_interval); } catch (const application_error& err) {
this->m_log.err("%s: %s", this->name(), err.what());
this->m_log.warn("Stopping '%s'...", this->name());
CAST_MODULE(Impl)->stop();
} }
} }
}; };
@ -387,25 +399,31 @@ namespace modules {
protected: protected:
void runner() { void runner() {
CAST_MODULE(Impl)->setup(); try {
CAST_MODULE(Impl)->setup();
// warmup
CAST_MODULE(Impl)->update();
CAST_MODULE(Impl)->broadcast();
while (CONST_CAST_MODULE(Impl).enabled()) {
std::unique_lock<threading_util::spin_lock> lck(this->update_lock);
if (!CAST_MODULE(Impl)->has_event())
continue;
if (!CAST_MODULE(Impl)->update())
continue;
// warmup
CAST_MODULE(Impl)->update();
CAST_MODULE(Impl)->broadcast(); CAST_MODULE(Impl)->broadcast();
lck.unlock(); while (CONST_CAST_MODULE(Impl).enabled()) {
CAST_MODULE(Impl)->idle(); std::unique_lock<threading_util::spin_lock> lck(this->update_lock);
if (!CAST_MODULE(Impl)->has_event())
continue;
if (!CAST_MODULE(Impl)->update())
continue;
CAST_MODULE(Impl)->broadcast();
lck.unlock();
CAST_MODULE(Impl)->idle();
}
} catch (const application_error& err) {
this->m_log.err("%s: %s", this->name(), err.what());
this->m_log.warn("Stopping '%s'...", this->name());
CAST_MODULE(Impl)->stop();
} }
} }
}; };
@ -425,18 +443,19 @@ namespace modules {
protected: protected:
void runner() { void runner() {
CAST_MODULE(Impl)->setup(); try {
CAST_MODULE(Impl)->on_event(nullptr); // warmup CAST_MODULE(Impl)->setup();
CAST_MODULE(Impl)->broadcast(); CAST_MODULE(Impl)->on_event(nullptr); // warmup
CAST_MODULE(Impl)->broadcast();
while (CAST_MODULE(Impl)->enabled()) { while (CAST_MODULE(Impl)->enabled()) {
std::lock_guard<threading_util::spin_lock> lck(this->update_lock); std::lock_guard<threading_util::spin_lock> lck(this->update_lock);
try {
CAST_MODULE(Impl)->poll_events(); CAST_MODULE(Impl)->poll_events();
} catch (const system_error& e) {
this->m_log.err("%s: Error while polling for events (what: %s)", this->name(), e.what());
return;
} }
} catch (const application_error& err) {
this->m_log.err("%s: %s", this->name(), err.what());
this->m_log.warn("Stopping '%s'...", this->name());
CAST_MODULE(Impl)->stop();
} }
} }

View File

@ -10,13 +10,17 @@ namespace modules {
using static_module::static_module; using static_module::static_module;
void setup() { void setup() {
m_formatter->add(FORMAT, "", {}); m_formatter->add("content", "", {});
if (m_formatter->get(FORMAT)->value.empty())
throw undefined_format(FORMAT); if (m_formatter->get("content")->value.empty())
throw module_error(name() + ".content is empty or undefined");
m_formatter->get("content")->value =
string_util::replace_all(m_formatter->get("content")->value, " ", BUILDER_SPACE_TOKEN);
} }
string get_format() { string get_format() {
return FORMAT; return "content";
} }
string get_output() { string get_output() {
@ -41,9 +45,6 @@ namespace modules {
return m_builder->flush(); return m_builder->flush();
} }
private:
static constexpr auto FORMAT = "content";
}; };
} }