fix:[NEXT-1916] Send all events, don't bail on errors#2384
Conversation
Ensure each item in the list is processed standalone and won't have any impact on other items in the list. Ensure each record is processed, not only the first record
WalkthroughThe SendNotification Lambda class is refactored to support batch processing of SNS records with improved error handling, JSON parsing, and logging. Import statements are made explicit, method signatures normalized, and a new helper method introduced to centralize publishing logic for both single and batch payloads. Changes
Estimated Code Review Effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✨ Finishing touches
Warning Review ran into problems🔥 ProblemsErrors were encountered while retrieving linked issues. Errors (1)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI Agents
In
@lambda-functions/notification-invoke-service/src/main/java/com/paladincloud/SendNotification.java:
- Around line 42-49: The code assumes policyParamsJson.getAsJsonArray("Records")
is non-null and uses forEach without per-record error handling; update the logic
in the method that builds and iterates Records (where policyParamsJson, records
and sendPayload are used) to first null-check the result of
policyParamsJson.getAsJsonArray("Records") and handle a missing key by logging
and returning/continuing as appropriate, and replace the current
records.forEach(...) with an explicit loop that wraps parsing of each record
(accessing "Sns" and "Message") and the call to sendPayload(payload, client,
snsTopicArn) in a try-catch so a failure for one record is logged (include
identifying context) and processing continues for remaining records.
🧹 Nitpick comments (3)
lambda-functions/notification-invoke-service/src/main/java/com/paladincloud/SendNotification.java (3)
34-34: Consider using try-with-resources or explicitly shutting down the SNS client.The
AmazonSNSclient is created but never closed. While Lambda containers handle cleanup, explicitly callingclient.shutdown()in a finally block is best practice to release resources promptly, especially for warmed containers processing many invocations.
59-73: Good per-item error handling; minor efficiency improvements possible.The per-item try-catch correctly isolates failures, aligning with the PR objective. However:
- Double JSON parsing (lines 60, 62) is inefficient.
.stream().forEach()is redundant—useforEach()directly on the list.🔎 Optional optimization
private void sendPayload(String payloadString, AmazonSNS client, String snsTopicArn) { - Object payloadObj = gson.fromJson(payloadString, Object.class); - if (payloadObj instanceof List) { - List<Object> notificationRequestList = gson.fromJson(payloadString, List.class); - notificationRequestList.stream().forEach(obj -> { + JsonElement payloadElement = JsonParser.parseString(payloadString); + if (payloadElement.isJsonArray()) { + JsonArray notificationRequestList = payloadElement.getAsJsonArray(); + for (JsonElement obj : notificationRequestList) { try { - String notificationRequestStr = gson.toJson(obj); + String notificationRequestStr = obj.toString(); LOGGER.info("notificationsrequeststr for list---{}", notificationRequestStr); PublishRequest request = new PublishRequest(snsTopicArn, notificationRequestStr); PublishResult result = client.publish(request); LOGGER.info("message sent with id {}", result.getMessageId()); } catch (Exception ex) { LOGGER.error("Failed sending message: {}", obj, ex); } - }); + } } else {
53-56: Inconsistent error handling: outer catch throws, inner catches log and continue.The outer catch (line 53-55) wraps and rethrows as
RuntimeException, whilesendPayloadcatches and logs per-item failures silently. Consider whether the Lambda should:
- Return a response indicating partial success/failure count, or
- Log the exception and return gracefully instead of throwing (for better observability in partial failure cases).
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
lambda-functions/notification-invoke-service/src/main/java/com/paladincloud/SendNotification.java
🧰 Additional context used
🧬 Code graph analysis (1)
lambda-functions/notification-invoke-service/src/main/java/com/paladincloud/SendNotification.java (1)
subsystem/auth/services/svc-api-authorizer/service/logging/logger.go (1)
Logger(26-28)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Analyze (javascript)
- GitHub Check: SonarCloud-Build
- GitHub Check: Analyze (java)
| JsonArray records = policyParamsJson.getAsJsonArray("Records"); | ||
|
|
||
| Object payloadObj = gson.fromJson(payloadString,Object.class); | ||
| if(payloadObj instanceof List){ | ||
| List<Object> notificationRequestList = gson.fromJson(payloadString,List.class); | ||
| notificationRequestList.stream().forEach(obj -> { | ||
| String notificationRequestStr = gson.toJson(obj); | ||
| LOGGER.info("notificationsrequeststr for list---"+notificationRequestStr); | ||
| PublishRequest request = new PublishRequest(snsTopicArn,notificationRequestStr); | ||
| PublishResult result = client.publish(request); | ||
| LOGGER.info("message sent with id "+result.getMessageId()); | ||
| records.forEach(body -> { | ||
| String payload = body.getAsJsonObject() | ||
| .get("Sns").getAsJsonObject() | ||
| .get("Message").getAsString(); | ||
| sendPayload(payload, client, snsTopicArn); | ||
| }); |
There was a problem hiding this comment.
Critical: Missing null check and per-record error handling contradicts PR objective.
Two issues here:
getAsJsonArray("Records")returnsnullif the key is absent, causing NPE on line 44.- The
forEachlacks try-catch around record parsing. If one record fails (e.g., missingSnsorMessage), processing stops for all remaining records—directly contradicting the PR objective.
🔎 Proposed fix
- JsonArray records = policyParamsJson.getAsJsonArray("Records");
-
- records.forEach(body -> {
- String payload = body.getAsJsonObject()
- .get("Sns").getAsJsonObject()
- .get("Message").getAsString();
- sendPayload(payload, client, snsTopicArn);
- });
+ JsonArray records = policyParamsJson.getAsJsonArray("Records");
+ if (records == null || records.isEmpty()) {
+ LOGGER.warn("No Records found in event");
+ return response;
+ }
+
+ for (JsonElement record : records) {
+ try {
+ String payload = record.getAsJsonObject()
+ .get("Sns").getAsJsonObject()
+ .get("Message").getAsString();
+ sendPayload(payload, client, snsTopicArn);
+ } catch (Exception ex) {
+ LOGGER.error("Failed to process record: {}", record, ex);
+ }
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| JsonArray records = policyParamsJson.getAsJsonArray("Records"); | |
| Object payloadObj = gson.fromJson(payloadString,Object.class); | |
| if(payloadObj instanceof List){ | |
| List<Object> notificationRequestList = gson.fromJson(payloadString,List.class); | |
| notificationRequestList.stream().forEach(obj -> { | |
| String notificationRequestStr = gson.toJson(obj); | |
| LOGGER.info("notificationsrequeststr for list---"+notificationRequestStr); | |
| PublishRequest request = new PublishRequest(snsTopicArn,notificationRequestStr); | |
| PublishResult result = client.publish(request); | |
| LOGGER.info("message sent with id "+result.getMessageId()); | |
| records.forEach(body -> { | |
| String payload = body.getAsJsonObject() | |
| .get("Sns").getAsJsonObject() | |
| .get("Message").getAsString(); | |
| sendPayload(payload, client, snsTopicArn); | |
| }); | |
| JsonArray records = policyParamsJson.getAsJsonArray("Records"); | |
| if (records == null || records.isEmpty()) { | |
| LOGGER.warn("No Records found in event"); | |
| return response; | |
| } | |
| for (JsonElement record : records) { | |
| try { | |
| String payload = record.getAsJsonObject() | |
| .get("Sns").getAsJsonObject() | |
| .get("Message").getAsString(); | |
| sendPayload(payload, client, snsTopicArn); | |
| } catch (Exception ex) { | |
| LOGGER.error("Failed to process record: {}", record, ex); | |
| } | |
| } |
🤖 Prompt for AI Agents
In
@lambda-functions/notification-invoke-service/src/main/java/com/paladincloud/SendNotification.java
around lines 42 - 49, The code assumes
policyParamsJson.getAsJsonArray("Records") is non-null and uses forEach without
per-record error handling; update the logic in the method that builds and
iterates Records (where policyParamsJson, records and sendPayload are used) to
first null-check the result of policyParamsJson.getAsJsonArray("Records") and
handle a missing key by logging and returning/continuing as appropriate, and
replace the current records.forEach(...) with an explicit loop that wraps
parsing of each record (accessing "Sns" and "Message") and the call to
sendPayload(payload, client, snsTopicArn) in a try-catch so a failure for one
record is logged (include identifying context) and processing continues for
remaining records.
Ensure each item in the list is processed standalone and won't have any impact on other items in the list. Ensure each record is processed, not only the first record
Summary by CodeRabbit
Release Notes
New Features
Bug Fixes
✏️ Tip: You can customize this high-level summary in your review settings.