Skip to content

Commit f5d608e

Browse files
Aditya-eddyclaude
andcommitted
review: address Copilot feedback on async-config-poll
- ConfigWatchService: read feature.enabled from the bucket's nested "keys" map (matching the config-stub's response shape) instead of the top level, where it never resolved. - ConfigWatchService: demote the per-poll "version advanced" log to DEBUG (the poller runs forever and the version can advance every poll), and log the poll exception object so a stack trace is available under DEBUG. - ConfigWatchService: make the boot-failure message actionable (check the config service is reachable / app.config.baseUrl is correct). - RulesResource: make the response-shape Javadoc example valid JSON. Content-Type feedback on /health and /rules is already handled by each method's @produces("application/json...") (recorded responses carry application/json), so no change there. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Aditya Sharma <aditya282003@gmail.com>
1 parent f138b26 commit f5d608e

2 files changed

Lines changed: 27 additions & 9 deletions

File tree

async-config-poll/src/main/java/com/example/asyncconfig/config/ConfigWatchService.java

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ public void init() {
5353
Map<String, Object> features = fetchBucket("app-features");
5454
Map<String, Object> appConfig = fetchBucket("app-config?watch=false"); // get current version
5555
this.appConfigVersion = intFrom(appConfig, "version", 0);
56-
Object flag = features == null ? null : features.get("feature.enabled");
57-
this.featuresEnabled = flag == null || Boolean.parseBoolean(String.valueOf(flag));
56+
// The config bucket carries flags under a nested "keys" map (see config-stub).
57+
this.featuresEnabled = boolFromKeys(features, "feature.enabled", true);
5858
log.info("ConfigWatchService initialized; featuresEnabled={} appConfigVersion={}",
5959
featuresEnabled, appConfigVersion);
6060

@@ -78,12 +78,15 @@ private void startWatchPoller() {
7878
int v = intFrom(resp, "version", appConfigVersion);
7979
if (v > appConfigVersion) {
8080
appConfigVersion = v;
81-
log.info("config watch: app-config advanced to version {}", v);
81+
// Debug, not info: the poller runs forever and the version
82+
// can advance on every poll, so info would flood normal runs.
83+
log.debug("config watch: app-config advanced to version {}", v);
8284
}
8385
} catch (Exception e) {
8486
// At replay the async engine keep-alives when nothing is
85-
// armed; a failed poll is non-fatal to the running app.
86-
log.debug("config watch poll failed: {}", e.getMessage());
87+
// armed; a failed poll is non-fatal to the running app. Pass
88+
// the exception so a stack trace is available under DEBUG.
89+
log.debug("config watch poll failed", e);
8790
}
8891
}
8992
}, "config-watch-poller");
@@ -103,8 +106,9 @@ private Map<String, Object> fetchBucket(String name) {
103106
return rt.getForObject(url, Map.class);
104107
} catch (Exception e) {
105108
throw new IllegalStateException(
106-
"ConfigWatchService: failed to fetch config bucket '" + name
107-
+ "' from " + url + " — application cannot boot", e);
109+
"ConfigWatchService: failed to fetch config bucket '" + name + "' from " + url
110+
+ " — application cannot boot. Ensure the config service is reachable and "
111+
+ "that app.config.baseUrl points at it.", e);
108112
}
109113
}
110114

@@ -119,6 +123,16 @@ private static int intFrom(Map<String, Object> m, String key, int dflt) {
119123
}
120124
}
121125

126+
/** Reads a boolean flag from the bucket's nested "keys" map (its real shape). */
127+
@SuppressWarnings("unchecked")
128+
private static boolean boolFromKeys(Map<String, Object> bucket, String key, boolean dflt) {
129+
if (bucket == null || !(bucket.get("keys") instanceof Map)) {
130+
return dflt;
131+
}
132+
Object v = ((Map<String, Object>) bucket.get("keys")).get(key);
133+
return v == null ? dflt : Boolean.parseBoolean(String.valueOf(v));
134+
}
135+
122136
public boolean isFeaturesEnabled() {
123137
return featuresEnabled;
124138
}

async-config-poll/src/main/java/com/example/asyncconfig/rules/RulesResource.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,12 @@
1717
/**
1818
* Rule-engine endpoint: GET /rules/{useCase}. Requires the X-Tenant-Id and
1919
* X-Agent-Id headers and returns the ordered rules for the (useCase, tenant),
20-
* read from MySQL:
21-
* [{"use_case","tenant","rules":[{"rule_id","constraints","actions":[...],"rule_type"}]}]
20+
* read from MySQL, e.g.:
21+
* <pre>
22+
* [{"use_case":"ORDER_FLOW","tenant":"ACME","rules":[
23+
* {"rule_id":14,"constraints":"...","rule_type":"POST","actions":[
24+
* {"basic_action":"...","action_details":"{}","sequence":1}]}]}]
25+
* </pre>
2226
*/
2327
@Component
2428
@Path("/rules")

0 commit comments

Comments
 (0)