Skip to content

Commit aa27439

Browse files
fix: old provider not shutting down when the new provider fails to initialize (#98)
## This PR Ensures that a displaced feature provider is always shut down when a new provider is set, preventing resource leaks when the new provider fails to initialize. Previously, the old provider was removed from the internal repository map immediately upon setting a new one, but `Shutdown()` was only called if the new provider successfully initialized. If the new provider's `Init()` failed, the old provider remained active but unreferenced, leaking its resources. ### Related Issues Fixes #69 --------- Signed-off-by: NeaguGeorgiana23 <neagugeorgiana@google.com>
1 parent da108c7 commit aa27439

3 files changed

Lines changed: 124 additions & 122 deletions

File tree

openfeature/provider_repository.cpp

Lines changed: 31 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "openfeature/provider_repository.h"
22

3+
#include <algorithm>
34
#include <iostream>
45

56
#include "absl/status/statusor.h"
@@ -30,9 +31,9 @@ ProviderRepository::GetFeatureProviderStatusManager(
3031
return default_manager_;
3132
}
3233

33-
auto it = provider_manager_.find(std::string(domain));
34-
if (it != provider_manager_.end()) {
35-
return it->second;
34+
auto provider_manager_it = provider_manager_.find(std::string(domain));
35+
if (provider_manager_it != provider_manager_.end()) {
36+
return provider_manager_it->second;
3637
}
3738

3839
return default_manager_;
@@ -49,32 +50,30 @@ std::shared_ptr<FeatureProvider> ProviderRepository::GetProvider(
4950
return nullptr;
5051
}
5152

52-
void ProviderRepository::SetProvider(std::shared_ptr<FeatureProvider> provider,
53-
const EvaluationContext& ctx,
54-
bool wait_for_init) {
53+
void ProviderRepository::SetProvider(
54+
const std::shared_ptr<FeatureProvider>& provider,
55+
const EvaluationContext& ctx, bool wait_for_init) {
5556
if (!provider) {
56-
std::cerr << "Provider cannot be null" << std::endl;
57+
std::cerr << "Provider cannot be null\n";
5758
return;
5859
}
59-
PrepareAndInitializeProvider(std::nullopt, std::move(provider), ctx,
60-
wait_for_init);
60+
PrepareAndInitializeProvider(std::nullopt, provider, ctx, wait_for_init);
6161
}
6262

63-
void ProviderRepository::SetProvider(std::string_view domain,
64-
std::shared_ptr<FeatureProvider> provider,
65-
const EvaluationContext& ctx,
66-
bool wait_for_init) {
63+
void ProviderRepository::SetProvider(
64+
std::string_view domain, const std::shared_ptr<FeatureProvider>& provider,
65+
const EvaluationContext& ctx, bool wait_for_init) {
6766
if (!provider) {
68-
std::cerr << "Provider cannot be null" << std::endl;
67+
std::cerr << "Provider cannot be null\n";
6968
return;
7069
}
7170

7271
if (domain.empty()) {
73-
SetProvider(std::move(provider), ctx, wait_for_init);
72+
SetProvider(provider, ctx, wait_for_init);
7473
return;
7574
}
7675

77-
PrepareAndInitializeProvider(std::string(domain), std::move(provider), ctx,
76+
PrepareAndInitializeProvider(std::string(domain), provider, ctx,
7877
wait_for_init);
7978
}
8079

@@ -90,7 +89,7 @@ ProviderStatus ProviderRepository::GetProviderStatus(
9089

9190
void ProviderRepository::Shutdown() {
9291
{
93-
std::lock_guard<std::mutex> lock(threads_mutex_);
92+
std::scoped_lock lock(threads_mutex_);
9493
for (std::thread& thread : initialization_threads_) {
9594
if (thread.joinable()) {
9695
thread.join();
@@ -128,9 +127,9 @@ void ProviderRepository::Shutdown() {
128127
}
129128

130129
void ProviderRepository::PrepareAndInitializeProvider(
131-
const std::optional<std::string> domain,
132-
std::shared_ptr<FeatureProvider> new_provider, const EvaluationContext& ctx,
133-
bool wait_for_init) {
130+
const std::optional<std::string>& domain,
131+
const std::shared_ptr<FeatureProvider>& new_provider,
132+
const EvaluationContext& ctx, bool wait_for_init) {
134133
std::shared_ptr<FeatureProviderStatusManager> new_status_manager;
135134
std::shared_ptr<FeatureProviderStatusManager> old_status_manager;
136135

@@ -144,7 +143,7 @@ void ProviderRepository::PrepareAndInitializeProvider(
144143
FeatureProviderStatusManager::Create(new_provider);
145144
if (!manager.ok()) {
146145
std::cerr << "Failed to create FeatureProviderStatusManager: "
147-
<< manager.status() << std::endl;
146+
<< manager.status() << "\n";
148147
return;
149148
}
150149
new_status_manager = std::move(manager.value());
@@ -154,9 +153,9 @@ void ProviderRepository::PrepareAndInitializeProvider(
154153

155154
if (domain) {
156155
// Setting a named provider.
157-
auto it = provider_manager_.find(domain.value());
158-
if (it != provider_manager_.end()) {
159-
old_status_manager = it->second;
156+
auto provider_manager_it = provider_manager_.find(domain.value());
157+
if (provider_manager_it != provider_manager_.end()) {
158+
old_status_manager = provider_manager_it->second;
160159
}
161160
provider_manager_[domain.value()] = new_status_manager;
162161
} else {
@@ -169,7 +168,7 @@ void ProviderRepository::PrepareAndInitializeProvider(
169168
if (wait_for_init) {
170169
InitializeProvider(new_status_manager, old_status_manager, ctx);
171170
} else {
172-
std::lock_guard<std::mutex> lock(threads_mutex_);
171+
std::scoped_lock lock(threads_mutex_);
173172
initialization_threads_.emplace_back(
174173
[this, new_status_manager, old_status_manager, ctx] {
175174
InitializeProvider(new_status_manager, old_status_manager, ctx);
@@ -178,20 +177,18 @@ void ProviderRepository::PrepareAndInitializeProvider(
178177
}
179178

180179
void ProviderRepository::InitializeProvider(
181-
std::shared_ptr<FeatureProviderStatusManager> new_status_manager,
182-
std::shared_ptr<FeatureProviderStatusManager> old_status_manager,
180+
const std::shared_ptr<FeatureProviderStatusManager>& new_status_manager,
181+
const std::shared_ptr<FeatureProviderStatusManager>& old_status_manager,
183182
const EvaluationContext& ctx) {
184183
if (new_status_manager->GetStatus() == ProviderStatus::kNotReady) {
185184
new_status_manager->Init(ctx);
186185
}
187186

188-
if (new_status_manager->GetStatus() == ProviderStatus::kReady) {
189-
ShutdownOldProvider(old_status_manager);
190-
}
187+
ShutdownOldProvider(old_status_manager);
191188
}
192189

193190
void ProviderRepository::ShutdownOldProvider(
194-
std::shared_ptr<FeatureProviderStatusManager> old_status_manager) {
191+
const std::shared_ptr<FeatureProviderStatusManager>& old_status_manager) {
195192
if (old_status_manager) {
196193
std::shared_lock<std::shared_mutex> lock(repo_mutex_);
197194

@@ -221,12 +218,9 @@ bool ProviderRepository::IsStatusManagerRegistered(
221218
if (default_manager_ == manager) {
222219
return true;
223220
}
224-
for (const auto& pair : provider_manager_) {
225-
if (pair.second == manager) {
226-
return true;
227-
}
228-
}
229-
return false;
221+
return std::any_of(
222+
provider_manager_.begin(), provider_manager_.end(),
223+
[&manager](const auto& pair) { return pair.second == manager; });
230224
}
231225

232226
} // namespace openfeature

openfeature/provider_repository.h

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,13 @@ class ProviderRepository {
4343
std::string_view domain = "") const;
4444

4545
// Set the default provider.
46-
void SetProvider(std::shared_ptr<FeatureProvider> provider,
47-
const EvaluationContext& ctx, bool waitForInit);
46+
void SetProvider(const std::shared_ptr<FeatureProvider>& provider,
47+
const EvaluationContext& ctx, bool wait_for_init);
4848

4949
// Add a provider for a domain.
5050
void SetProvider(std::string_view domain,
51-
std::shared_ptr<FeatureProvider> provider,
52-
const EvaluationContext& ctx, bool waitForInit);
51+
const std::shared_ptr<FeatureProvider>& provider,
52+
const EvaluationContext& ctx, bool wait_for_init);
5353

5454
// Fetch the status of a provider for a domain.
5555
// If the domain is not set, return the default provider status.
@@ -63,17 +63,17 @@ class ProviderRepository {
6363

6464
private:
6565
void PrepareAndInitializeProvider(
66-
const std::optional<std::string> domain,
67-
std::shared_ptr<FeatureProvider> new_provider,
68-
const EvaluationContext& ctx, bool waitForInit);
66+
const std::optional<std::string>& domain,
67+
const std::shared_ptr<FeatureProvider>& new_provider,
68+
const EvaluationContext& ctx, bool wait_for_init);
6969

7070
void InitializeProvider(
71-
std::shared_ptr<FeatureProviderStatusManager> new_status_manager,
72-
std::shared_ptr<FeatureProviderStatusManager> old_status_manager,
71+
const std::shared_ptr<FeatureProviderStatusManager>& new_status_manager,
72+
const std::shared_ptr<FeatureProviderStatusManager>& old_status_manager,
7373
const EvaluationContext& ctx);
7474

7575
void ShutdownOldProvider(
76-
std::shared_ptr<FeatureProviderStatusManager> old_status_manager);
76+
const std::shared_ptr<FeatureProviderStatusManager>& old_status_manager);
7777

7878
std::shared_ptr<FeatureProviderStatusManager>
7979
GetExistingStatusManagerForProvider(

0 commit comments

Comments
 (0)