Skip to content

Commit 472a3ea

Browse files
committed
Implement a mutex lock to prevent multiple threads from finding the same exit node (#143)
1 parent 9e34113 commit 472a3ea

File tree

1 file changed

+13
-3
lines changed

1 file changed

+13
-3
lines changed

src/daemon.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ pub const SVCS_FINALIZER: &str = "service.chisel-operator.io/finalizer";
7474
// this is actually used to pass clients around
7575
pub struct Context {
7676
pub client: Client,
77+
// Let's implement a lock here to prevent multiple reconciles assigning the same exit node
78+
// to multiple services implicitly (#143)
79+
pub exit_node_lock: tokio::sync::Mutex<()>,
7780
}
7881

7982
/// Parses the `query` string to extract the namespace and name.
@@ -167,9 +170,11 @@ const OPERATOR_MANAGER: &str = "chisel-operator";
167170

168171
#[instrument(skip(ctx))]
169172
async fn select_exit_node_local(
170-
ctx: Arc<Context>,
173+
ctx: &Arc<Context>,
171174
service: &Service,
172175
) -> Result<ExitNode, ReconcileError> {
176+
// Lock to prevent race conditions when assigning exit nodes to services
177+
let _lock = ctx.exit_node_lock.lock().await;
173178
// if service has label with exit node name, use that and error if not found
174179
if let Some(exit_node_name) = service
175180
.metadata
@@ -369,7 +374,7 @@ async fn reconcile_svcs(obj: Arc<Service>, ctx: Arc<Context>) -> Result<Action,
369374
// Else, use the first available exit node
370375
// Fails if there's no empty exit node available
371376
else {
372-
select_exit_node_local(ctx.clone(), &obj).await?
377+
select_exit_node_local(&ctx, &obj).await?
373378
}
374379
};
375380

@@ -716,6 +721,7 @@ pub async fn run() -> color_eyre::Result<()> {
716721
// TODO: figure out how to do this in a single controller because there is a potential race where the exit node reconciler runs at the same time as the service one
717722
// This is an issue because both of these functions patch the status of the exit node
718723
// or if we can figure out a way to atomically patch the status of the exit node, that could be fine too, since both ops are just updates anyways lmfao
724+
// NOTE: Maybe we could use a lock to prevent this. This will be implemented only for local exit nodes for now.
719725

720726
reconcilers.push(
721727
Controller::new(services, Config::default())
@@ -737,6 +743,7 @@ pub async fn run() -> color_eyre::Result<()> {
737743
error_policy,
738744
Arc::new(Context {
739745
client: client.clone(),
746+
exit_node_lock: tokio::sync::Mutex::new(()),
740747
}),
741748
)
742749
.for_each(|_| futures::future::ready(()))
@@ -762,7 +769,10 @@ pub async fn run() -> color_eyre::Result<()> {
762769
.run(
763770
reconcile_nodes,
764771
error_policy_exit_node,
765-
Arc::new(Context { client }),
772+
Arc::new(Context {
773+
client,
774+
exit_node_lock: tokio::sync::Mutex::new(()),
775+
}),
766776
)
767777
.for_each(|_| futures::future::ready(()))
768778
.boxed(),

0 commit comments

Comments
 (0)