Skip to content

Commit c13f1d8

Browse files
committed
refactor: catch exceptions in DynamoDB Big Segments lookups
1 parent 8153023 commit c13f1d8

1 file changed

Lines changed: 95 additions & 80 deletions

File tree

libs/server-sdk-dynamodb-source/src/dynamodb_big_segment_store.cpp

Lines changed: 95 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -65,99 +65,114 @@ DynamoDBBigSegmentStore::~DynamoDBBigSegmentStore() = default;
6565

6666
IBigSegmentStore::GetMembershipResult DynamoDBBigSegmentStore::GetMembership(
6767
std::string const& context_hash) const noexcept {
68-
Aws::DynamoDB::Model::GetItemRequest request;
69-
request.SetTableName(table_name_);
70-
request.SetConsistentRead(true);
71-
request.AddKey(kPartitionKey,
72-
Aws::DynamoDB::Model::AttributeValue{user_namespace_});
73-
request.AddKey(kSortKey,
74-
Aws::DynamoDB::Model::AttributeValue{context_hash});
75-
76-
auto outcome = client_->GetItem(request);
77-
if (!outcome.IsSuccess()) {
78-
return tl::make_unexpected(outcome.GetError().GetMessage());
79-
}
80-
81-
auto const& item = outcome.GetResult().GetItem();
82-
83-
std::vector<std::string> included;
84-
std::vector<std::string> excluded;
85-
86-
// GetSS() silently returns an empty vector if the attribute is not
87-
// actually a String Set, so check the type explicitly before reading.
88-
if (auto const it = item.find(kBigSegmentsIncludedAttribute);
89-
it != item.end()) {
90-
if (it->second.GetType() !=
91-
Aws::DynamoDB::Model::ValueType::STRING_SET) {
92-
return tl::make_unexpected(std::string("DynamoDB Big Segments '") +
93-
kBigSegmentsIncludedAttribute +
94-
"' is not of type STRING_SET");
95-
}
96-
for (auto const& ref : it->second.GetSS()) {
97-
included.emplace_back(ref);
68+
try {
69+
Aws::DynamoDB::Model::GetItemRequest request;
70+
request.SetTableName(table_name_);
71+
request.SetConsistentRead(true);
72+
request.AddKey(kPartitionKey,
73+
Aws::DynamoDB::Model::AttributeValue{user_namespace_});
74+
request.AddKey(kSortKey,
75+
Aws::DynamoDB::Model::AttributeValue{context_hash});
76+
77+
auto outcome = client_->GetItem(request);
78+
if (!outcome.IsSuccess()) {
79+
return tl::make_unexpected(outcome.GetError().GetMessage());
9880
}
99-
}
100-
if (auto const it = item.find(kBigSegmentsExcludedAttribute);
101-
it != item.end()) {
102-
if (it->second.GetType() !=
103-
Aws::DynamoDB::Model::ValueType::STRING_SET) {
104-
return tl::make_unexpected(std::string("DynamoDB Big Segments '") +
105-
kBigSegmentsExcludedAttribute +
106-
"' is not of type STRING_SET");
81+
82+
auto const& item = outcome.GetResult().GetItem();
83+
84+
std::vector<std::string> included;
85+
std::vector<std::string> excluded;
86+
87+
// GetSS() silently returns an empty vector if the attribute is not
88+
// actually a String Set, so check the type explicitly before reading.
89+
if (auto const it = item.find(kBigSegmentsIncludedAttribute);
90+
it != item.end()) {
91+
if (it->second.GetType() !=
92+
Aws::DynamoDB::Model::ValueType::STRING_SET) {
93+
return tl::make_unexpected(
94+
std::string("DynamoDB Big Segments '") +
95+
kBigSegmentsIncludedAttribute +
96+
"' is not of type STRING_SET");
97+
}
98+
for (auto const& ref : it->second.GetSS()) {
99+
included.emplace_back(ref);
100+
}
107101
}
108-
for (auto const& ref : it->second.GetSS()) {
109-
excluded.emplace_back(ref);
102+
if (auto const it = item.find(kBigSegmentsExcludedAttribute);
103+
it != item.end()) {
104+
if (it->second.GetType() !=
105+
Aws::DynamoDB::Model::ValueType::STRING_SET) {
106+
return tl::make_unexpected(
107+
std::string("DynamoDB Big Segments '") +
108+
kBigSegmentsExcludedAttribute +
109+
"' is not of type STRING_SET");
110+
}
111+
for (auto const& ref : it->second.GetSS()) {
112+
excluded.emplace_back(ref);
113+
}
110114
}
111-
}
112115

113-
return Membership::FromSegmentRefs(included, excluded);
116+
return Membership::FromSegmentRefs(included, excluded);
117+
} catch (std::exception const& e) {
118+
return tl::make_unexpected(e.what());
119+
}
114120
}
115121

116122
IBigSegmentStore::GetMetadataResult DynamoDBBigSegmentStore::GetMetadata()
117123
const noexcept {
118-
Aws::DynamoDB::Model::GetItemRequest request;
119-
request.SetTableName(table_name_);
120-
request.SetConsistentRead(true);
121-
request.AddKey(kPartitionKey,
122-
Aws::DynamoDB::Model::AttributeValue{metadata_namespace_});
123-
request.AddKey(kSortKey,
124-
Aws::DynamoDB::Model::AttributeValue{metadata_namespace_});
125-
126-
auto outcome = client_->GetItem(request);
127-
if (!outcome.IsSuccess()) {
128-
return tl::make_unexpected(outcome.GetError().GetMessage());
129-
}
124+
try {
125+
Aws::DynamoDB::Model::GetItemRequest request;
126+
request.SetTableName(table_name_);
127+
request.SetConsistentRead(true);
128+
request.AddKey(
129+
kPartitionKey,
130+
Aws::DynamoDB::Model::AttributeValue{metadata_namespace_});
131+
request.AddKey(
132+
kSortKey,
133+
Aws::DynamoDB::Model::AttributeValue{metadata_namespace_});
134+
135+
auto outcome = client_->GetItem(request);
136+
if (!outcome.IsSuccess()) {
137+
return tl::make_unexpected(outcome.GetError().GetMessage());
138+
}
130139

131-
auto const& item = outcome.GetResult().GetItem();
132-
if (item.empty()) {
133-
return std::nullopt;
134-
}
140+
auto const& item = outcome.GetResult().GetItem();
141+
if (item.empty()) {
142+
return std::nullopt;
143+
}
135144

136-
auto const it = item.find(kBigSegmentsSyncTimeAttribute);
137-
if (it == item.end()) {
138-
// "absent" sync time is treated as never synchronized rather than
139-
// an error; the wrapper marks the store stale based on the
140-
// resulting nullopt.
141-
return std::nullopt;
142-
}
145+
auto const it = item.find(kBigSegmentsSyncTimeAttribute);
146+
if (it == item.end()) {
147+
// "absent" sync time is treated as never synchronized rather than
148+
// an error; the wrapper marks the store stale based on the
149+
// resulting nullopt.
150+
return std::nullopt;
151+
}
143152

144-
auto const& raw = it->second.GetN();
145-
if (raw.empty()) {
146-
return tl::make_unexpected(
147-
"DynamoDB Big Segments 'synchronizedOn' is empty or not type N");
148-
}
153+
auto const& raw = it->second.GetN();
154+
if (raw.empty()) {
155+
return tl::make_unexpected(
156+
"DynamoDB Big Segments 'synchronizedOn' is empty or not type "
157+
"N");
158+
}
149159

150-
errno = 0;
151-
char* end = nullptr;
152-
long long const parsed = std::strtoll(raw.c_str(), &end, 10);
153-
if (errno != 0 || end == raw.c_str() || *end != '\0') {
154-
return tl::make_unexpected(
155-
"DynamoDB Big Segments 'synchronizedOn' is not a valid integer");
156-
}
160+
errno = 0;
161+
char* end = nullptr;
162+
long long const parsed = std::strtoll(raw.c_str(), &end, 10);
163+
if (errno != 0 || end == raw.c_str() || *end != '\0') {
164+
return tl::make_unexpected(
165+
"DynamoDB Big Segments 'synchronizedOn' is not a valid "
166+
"integer");
167+
}
157168

158-
// The stored value is a Unix-epoch millisecond count: system_clock's epoch.
159-
return StoreMetadata{std::chrono::system_clock::time_point{
160-
std::chrono::milliseconds{parsed}}};
169+
// The stored value is a Unix-epoch millisecond count: system_clock's
170+
// epoch.
171+
return StoreMetadata{std::chrono::system_clock::time_point{
172+
std::chrono::milliseconds{parsed}}};
173+
} catch (std::exception const& e) {
174+
return tl::make_unexpected(e.what());
175+
}
161176
}
162177

163178
} // namespace launchdarkly::server_side::integrations

0 commit comments

Comments
 (0)