Add support for autorestart in aos_starter
We have applications which we want to run only once (at startup or
during runtime). This enables the user to configure the state machine
to support the behavior they want.
Change-Id: Ica59338956eb1cadd2edac49fbdac51b56aa516a
Signed-off-by: James Kuszmaul <james.kuszmaul@bluerivertech.com>
diff --git a/aos/configuration.fbs b/aos/configuration.fbs
index 3401b43..c0d67b0 100644
--- a/aos/configuration.fbs
+++ b/aos/configuration.fbs
@@ -146,6 +146,9 @@
// Indicates that application should be executed on boot.
autostart:bool = true (id: 6);
+
+ // Indicates that application should automatically restart on failure.
+ autorestart:bool = true (id: 7);
}
// Per node data and connection information.
diff --git a/aos/events/logging/logger_test.cc b/aos/events/logging/logger_test.cc
index 7a569eb..1f784d3 100644
--- a/aos/events/logging/logger_test.cc
+++ b/aos/events/logging/logger_test.cc
@@ -2614,9 +2614,9 @@
}
constexpr std::string_view kCombinedConfigSha1(
- "9e07da76098ad1b755a7c3143aca300d66b6abb88745f6c36e603ef1441f0ad5");
+ "b8114cd99e9c606b7517d8f478bf16513aef550f23f317720667314cb261f689");
constexpr std::string_view kSplitConfigSha1(
- "85ef8be228bf4eb36f4d64ba68183b2a9a616bfb9b057e430d61e33bd273df86");
+ "60943d0a46afa6028c8ae276e7b4900b35892f1f53b1818056e7d04463709c5b");
INSTANTIATE_TEST_SUITE_P(
All, MultinodeLoggerTest,
diff --git a/aos/starter/BUILD b/aos/starter/BUILD
index 73353f6..ec323a9 100644
--- a/aos/starter/BUILD
+++ b/aos/starter/BUILD
@@ -65,7 +65,7 @@
"//aos/events:pong",
],
linkopts = ["-lstdc++fs"],
- shard_count = 3,
+ shard_count = 4,
# The roborio compiler doesn't support <filesystem>.
target_compatible_with =
select({
diff --git a/aos/starter/starter_test.cc b/aos/starter/starter_test.cc
index f434e84..120fe38 100644
--- a/aos/starter/starter_test.cc
+++ b/aos/starter/starter_test.cc
@@ -316,5 +316,95 @@
starterd_thread.join();
}
+// Tests that starterd respects autorestart.
+TEST_F(StarterdTest, DeathNoRestartTest) {
+ const std::string config_file =
+ ArtifactPath("aos/events/pingpong_config.json");
+
+ aos::FlatbufferDetachedBuffer<aos::Configuration> config =
+ aos::configuration::ReadConfig(config_file);
+
+ const std::string test_dir = aos::testing::TestTmpDir();
+
+ auto new_config = aos::configuration::MergeWithConfig(
+ &config.message(), absl::StrFormat(
+ R"({"applications": [
+ {
+ "name": "ping",
+ "executable_name": "%s",
+ "args": ["--shm_base", "%s/aos"],
+ "autorestart": false
+ },
+ {
+ "name": "pong",
+ "executable_name": "%s",
+ "args": ["--shm_base", "%s/aos"]
+ }
+ ]})",
+ ArtifactPath("aos/events/ping"), test_dir,
+ ArtifactPath("aos/events/pong"), test_dir));
+
+ const aos::Configuration *config_msg = &new_config.message();
+
+ // Set up starter with config file
+ aos::starter::Starter starter(config_msg);
+
+ // Create an event loop to watch for the Status message to watch the state
+ // transitions.
+ aos::ShmEventLoop watcher_loop(config_msg);
+ watcher_loop.SkipAosLog();
+
+ watcher_loop
+ .AddTimer([&watcher_loop] {
+ watcher_loop.Exit();
+ SUCCEED();
+ })
+ ->Setup(watcher_loop.monotonic_now() + std::chrono::seconds(11));
+
+ int test_stage = 0;
+ uint64_t id;
+
+ watcher_loop.MakeWatcher("/aos", [&test_stage, &watcher_loop,
+ &id](const aos::starter::Status &status) {
+ const aos::starter::ApplicationStatus *app_status =
+ FindApplicationStatus(status, "ping");
+ if (app_status == nullptr) {
+ return;
+ }
+
+ switch (test_stage) {
+ case 0: {
+ if (app_status->has_state() &&
+ app_status->state() == aos::starter::State::RUNNING) {
+ LOG(INFO) << "Ping is running";
+ test_stage = 1;
+ ASSERT_TRUE(app_status->has_pid());
+ ASSERT_TRUE(kill(app_status->pid(), SIGINT) != -1);
+ ASSERT_TRUE(app_status->has_id());
+ id = app_status->id();
+ }
+ break;
+ }
+
+ case 1: {
+ if (app_status->has_state() &&
+ app_status->state() == aos::starter::State::RUNNING &&
+ app_status->has_id() && app_status->id() != id) {
+ LOG(INFO) << "Ping restarted, it shouldn't...";
+ watcher_loop.Exit();
+ FAIL();
+ }
+ break;
+ }
+ }
+ });
+
+ std::thread starterd_thread([&starter] { starter.Run(); });
+ watcher_loop.Run();
+
+ starter.Cleanup();
+ starterd_thread.join();
+}
+
} // namespace starter
} // namespace aos
diff --git a/aos/starter/starterd_lib.cc b/aos/starter/starterd_lib.cc
index 00b094f..b7c49ed 100644
--- a/aos/starter/starterd_lib.cc
+++ b/aos/starter/starterd_lib.cc
@@ -31,6 +31,7 @@
group_(application->has_user() ? FindPrimaryGidForUser(user_name_.c_str())
: std::nullopt),
autostart_(application->autostart()),
+ autorestart_(application->autorestart()),
event_loop_(event_loop),
start_timer_(event_loop_->AddTimer([this] {
status_ = aos::starter::State::RUNNING;
@@ -319,13 +320,17 @@
case aos::starter::State::STARTING: {
LOG(WARNING) << "Failed to start '" << name_ << "' on pid " << pid_
<< " : Exited with status " << exit_code_;
- QueueStart();
+ if (autorestart()) {
+ QueueStart();
+ }
break;
}
case aos::starter::State::RUNNING: {
LOG(WARNING) << "Application '" << name_ << "' pid " << pid_
<< " exited unexpectedly with status " << exit_code_;
- QueueStart();
+ if (autorestart()) {
+ QueueStart();
+ }
break;
}
case aos::starter::State::STOPPING: {
diff --git a/aos/starter/starterd_lib.h b/aos/starter/starterd_lib.h
index 8c70960..e1f82a0 100644
--- a/aos/starter/starterd_lib.h
+++ b/aos/starter/starterd_lib.h
@@ -97,6 +97,8 @@
bool autostart() const { return autostart_; }
+ bool autorestart() const { return autorestart_; }
+
private:
void DoStart();
@@ -130,6 +132,7 @@
bool queue_restart_ = false;
bool terminating_ = false;
bool autostart_ = true;
+ bool autorestart_ = true;
aos::starter::State status_ = aos::starter::State::STOPPED;
aos::starter::LastStopReason stop_reason_ =