Skip to content

Commit 6a14284

Browse files
committed
feat: Add graceful shutdown
1 parent ab14b18 commit 6a14284

7 files changed

Lines changed: 74 additions & 55 deletions

File tree

Cargo.lock

Lines changed: 13 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.nix

Lines changed: 23 additions & 23 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ edition = "2021"
1010
repository = "https://github.com/stackabletech/commons-operator"
1111

1212
[workspace.dependencies]
13-
stackable-operator = { git = "https://github.com/stackabletech/operator-rs.git", tag = "stackable-operator-0.101.1", features = ["telemetry", "webhook"] }
13+
stackable-operator = { git = "https://github.com/stackabletech/operator-rs.git", tag = "stackable-operator-0.105.0", features = ["telemetry", "webhook"] }
1414

1515
anyhow = "1.0"
1616
built = { version = "0.8", features = ["chrono", "git2"] }

crate-hashes.json

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/operator-binary/src/main.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use stackable_operator::{
1616
eos::EndOfSupportChecker,
1717
shared::yaml::SerializeOptions,
1818
telemetry::Tracing,
19+
utils::signal::SignalWatcher,
1920
};
2021
use webhook::create_webhook_server;
2122

@@ -90,9 +91,13 @@ async fn main() -> anyhow::Result<()> {
9091
description = built_info::PKG_DESCRIPTION
9192
);
9293

94+
// Watches for the SIGTERM signal and sends a signal to all receivers, which gracefully
95+
// shuts down all concurrent tasks below (EoS checker, controller).
96+
let sigterm_watcher = SignalWatcher::sigterm()?;
97+
9398
let eos_checker =
9499
EndOfSupportChecker::new(built_info::BUILT_TIME_UTC, maintenance.end_of_support)?
95-
.run()
100+
.run(sigterm_watcher.handle())
96101
.map(anyhow::Ok);
97102

98103
let client = stackable_operator::client::initialize_operator(
@@ -107,10 +112,13 @@ async fn main() -> anyhow::Result<()> {
107112
cm_store_tx,
108113
secret_store_tx,
109114
&watch_namespace,
115+
sigterm_watcher.handle(),
110116
)
111117
.map(anyhow::Ok);
118+
112119
let pod_restart_controller =
113-
restart_controller::pod::start(&client, &watch_namespace).map(anyhow::Ok);
120+
restart_controller::pod::start(&client, &watch_namespace, sigterm_watcher.handle())
121+
.map(anyhow::Ok);
114122

115123
let webhook_server = create_webhook_server(
116124
ctx,
@@ -119,8 +127,9 @@ async fn main() -> anyhow::Result<()> {
119127
client.as_kube_client(),
120128
)
121129
.await?;
130+
122131
let webhook_server = webhook_server
123-
.run()
132+
.run(sigterm_watcher.handle())
124133
.map_err(|err| anyhow!(err).context("failed to run webhook"));
125134

126135
futures::try_join!(

rust/operator-binary/src/restart_controller/pod.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{sync::Arc, time::Duration};
1+
use std::{future::Future, sync::Arc, time::Duration};
22

33
use futures::StreamExt;
44
use http::StatusCode;
@@ -70,7 +70,10 @@ impl ReconcilerError for Error {
7070
}
7171
}
7272

73-
pub async fn start(client: &Client, watch_namespace: &WatchNamespace) {
73+
pub async fn start<F>(client: &Client, watch_namespace: &WatchNamespace, shutdown_signal: F)
74+
where
75+
F: Future<Output = ()> + Send + Sync + 'static,
76+
{
7477
let controller = Controller::new(
7578
watch_namespace.get_api::<PartialObjectMeta<Pod>>(client),
7679
// TODO: Can we only watch a subset of Pods with a specify label, e.g.
@@ -85,6 +88,7 @@ pub async fn start(client: &Client, watch_namespace: &WatchNamespace) {
8588
},
8689
));
8790
controller
91+
.graceful_shutdown_on(shutdown_signal)
8892
.run(
8993
reconcile,
9094
error_policy,

rust/operator-binary/src/restart_controller/statefulset.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{collections::BTreeMap, sync::Arc, time::Duration};
1+
use std::{collections::BTreeMap, future::Future, sync::Arc, time::Duration};
22

33
use futures::{Stream, StreamExt, TryStream, stream};
44
use serde_json::json;
@@ -92,12 +92,15 @@ pub fn create_context(
9292
(ctx, cm_store_tx, secret_store_tx)
9393
}
9494

95-
pub async fn start(
95+
pub async fn start<F>(
9696
ctx: Arc<Ctx>,
9797
cm_store_tx: Initializer<Store<PartialObjectMeta<ConfigMap>>>,
9898
secret_store_tx: Initializer<Store<PartialObjectMeta<Secret>>>,
9999
watch_namespace: &WatchNamespace,
100-
) {
100+
shutdown_signal: F,
101+
) where
102+
F: Future<Output = ()>,
103+
{
101104
let stses = watch_namespace.get_api::<DeserializeGuard<StatefulSet>>(&ctx.client);
102105
let cms = watch_namespace.get_api::<ConfigMap>(&ctx.client);
103106
let secrets = watch_namespace.get_api::<Secret>(&ctx.client);
@@ -163,7 +166,10 @@ pub async fn start(
163166
.applied_objects(),
164167
(),
165168
),
166-
),
169+
)
170+
// This uses the same mechanism as kube's Controller does under the hood, see
171+
// https://github.com/kube-rs/kube/blob/8bcdcb52e1e13c1c1ec59f6118fbed575ac10a4b/kube-runtime/src/controller/mod.rs#L1671
172+
.take_until(shutdown_signal),
167173
Config::default(),
168174
)
169175
// We can let the reporting happen in the background

0 commit comments

Comments
 (0)