Skip to content

Conversation

@predic8
Copy link
Member

@predic8 predic8 commented Dec 8, 2025

Summary by CodeRabbit

  • Documentation

    • Converted configuration examples from XML to YAML throughout docs and reorganized examples around YAML roots
    • Added note requiring Membrane 7.0.0+ for YAML samples
    • Updated authentication (API key/JWT) and dynamic destination/load-balancing examples and ports
    • Minor wording and structure improvements for clarity
  • Chores

    • Adjusted startup/initialization flow for YAML-based configuration processing (improves deterministic activation)

✏️ Tip: You can customize this high-level summary in your review settings.

- Added `start()` method to `BeanRegistry` interface and its implementation for lifecycle management. - Documented thread-safety expectations and constraints for `registerBeanDefinitions()` and `start()`. - Updated usage in relevant classes to adhere to the modified lifecycle flow.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 8, 2025

Walkthrough

Added lifecycle methods to the BeanRegistry API—registerBeanDefinitions(List<BeanDefinition>) and start()—and updated callers to register then start. Documentation converted many README XML examples to YAML and added a Membrane 7.0.0+ note. Activation ordering changed from Set to List.

Changes

Cohort / File(s) Change Summary
BeanRegistry interface additions
annot/src/main/java/com/predic8/membrane/annot/yaml/BeanRegistry.java
Added registerBeanDefinitions(List<BeanDefinition>) and start() with expanded Javadoc describing thread-safety, lifecycle, and execution semantics.
BeanRegistry implementation & activation ordering
annot/src/main/java/com/predic8/membrane/annot/yaml/BeanRegistryImplementation.java
Implemented registerBeanDefinitions(List<BeanDefinition>), adjusted internal collections (uidsToActivate changed from SetList, bds map type simplified), and updated docs/comments about activation processing and Kubernetes behavior.
Call-site updates (register → start)
annot/src/test/java/.../YamlParser.java, core/src/main/java/.../RouterCLI.java, core/src/test/java/.../GenericYamlParserTest.java
Callers now create a BeanRegistry, call registerBeanDefinitions(...) and then start(). Test registry includes an empty start() override to satisfy the interface.
Documentation: XML → YAML migration
README.md
Replaced many XML configuration fragments with YAML equivalents, added “requires Membrane version 7.0.0 or newer” for YAML samples, updated ports/examples and minor wording tweaks.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Pay attention to thread-safety and lifecycle semantics in BeanRegistryImplementation.registerBeanDefinitions.
  • Verify Set→List change (uidsToActivate) preserves intended activation order and concurrency assumptions.
  • Confirm all call sites correctly sequence registration before start() to avoid init-time races.

Possibly related PRs

Suggested labels

7.x

Suggested reviewers

  • rrayst
  • christiangoerdes

Poem

🐰 Beans in YAML, tidy and bright,
I hop to start them, one by one at night,
Register, then start — orderly cheer,
Ports updated, docs now clear,
A tiny hop for code, a joyful bite.

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'Readme yaml snippets' is partially related to the changeset but oversimplifies the scope. While YAML snippets in README are a major change, the PR also introduces critical API changes to BeanRegistry interface and implementation affecting multiple modules. Consider a more comprehensive title such as 'Add BeanRegistry lifecycle methods and migrate README examples to YAML' to reflect both documentation updates and API additions.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch readme-yaml-snippets

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6b4f20e and df0eae9.

📒 Files selected for processing (1)
  • README.md (14 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-11-23T15:59:51.742Z
Learnt from: rrayst Repo: membrane/api-gateway PR: 2339 File: distribution/examples/web-services-soap/rest2soap-template/apis.yaml:17-32 Timestamp: 2025-11-23T15:59:51.742Z Learning: In Membrane API Gateway YAML configuration files, response flows execute in reverse order. Steps that appear later in the response flow list actually execute first. For example, if a template references properties and setProperty steps appear after the template in the YAML, those setProperty steps will execute before the template renders. 

Applied to files:

  • README.md
⏰ 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). (2)
  • GitHub Check: Analyze (java)
  • GitHub Check: Automated tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
annot/src/main/java/com/predic8/membrane/annot/yaml/BeanRegistryImplementation.java (1)

113-129: The start() method exits prematurely in Kubernetes mode, leaving enqueued events unconsumed.

The current implementation calls beanRegistry.start() once during Router startup (Router.java:304) on the main thread. The method processes initial events and exits when the queue is empty (while (!changeEvents.isEmpty())). However, Kubernetes watchers are created after start() returns and asynchronously add events via beanRegistry.handle(). These events accumulate in the queue with no consumer running to process them.

The Javadoc explicitly states: "In Kubernetes mode, run this method in a dedicated long-running thread to consume update events as they arrive," but the implementation contradicts this. Using a poison pill or shutdown signal instead of queue emptiness as the termination condition would allow start() to block indefinitely when running in a dedicated consumer thread, properly handling continuous Kubernetes events.

🧹 Nitpick comments (2)
core/src/main/java/com/predic8/membrane/core/cli/RouterCLI.java (1)

159-161: Avoid instantiating GrammarAutoGenerated twice.

GrammarAutoGenerated is created twice on consecutive lines. Extract it to a local variable to avoid redundant instantiation and ensure consistency.

 private static Router initRouterByYAML(String location) throws Exception { var router = new HttpRouter(); router.setBaseLocation(location); router.setHotDeploy(false); router.setAsynchronousInitialization(true); router.start(); - BeanRegistry registry = new BeanRegistryImplementation(router, new GrammarAutoGenerated()); - registry.registerBeanDefinitions(parseMembraneResources(router.getResolverMap().resolve(location), new GrammarAutoGenerated())); + var grammar = new GrammarAutoGenerated(); + BeanRegistry registry = new BeanRegistryImplementation(router, grammar); + registry.registerBeanDefinitions(parseMembraneResources(router.getResolverMap().resolve(location), grammar)); registry.start(); return router; }
annot/src/main/java/com/predic8/membrane/annot/yaml/BeanRegistryImplementation.java (1)

201-202: Inefficient removal from List.

Removing elements from an ArrayList via remove(Object) in a loop is O(n) per removal, resulting in O(n²) overall. For small lists this is acceptable, but if the activation list grows large, consider using removeAll(uidsToRemove) or switching to a data structure that supports O(1) removal.

- for (String uid : uidsToRemove) - uidsToActivate.remove(uid); + uidsToActivate.removeAll(uidsToRemove);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9b7235c and 6b4f20e.

📒 Files selected for processing (6)
  • README.md (14 hunks)
  • annot/src/main/java/com/predic8/membrane/annot/yaml/BeanRegistry.java (1 hunks)
  • annot/src/main/java/com/predic8/membrane/annot/yaml/BeanRegistryImplementation.java (1 hunks)
  • annot/src/test/java/com/predic8/membrane/annot/util/YamlParser.java (1 hunks)
  • core/src/main/java/com/predic8/membrane/core/cli/RouterCLI.java (1 hunks)
  • core/src/test/java/com/predic8/membrane/core/kubernetes/GenericYamlParserTest.java (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-11-23T15:59:51.742Z
Learnt from: rrayst Repo: membrane/api-gateway PR: 2339 File: distribution/examples/web-services-soap/rest2soap-template/apis.yaml:17-32 Timestamp: 2025-11-23T15:59:51.742Z Learning: In Membrane API Gateway YAML configuration files, response flows execute in reverse order. Steps that appear later in the response flow list actually execute first. For example, if a template references properties and setProperty steps appear after the template in the YAML, those setProperty steps will execute before the template renders. 

Applied to files:

  • README.md
⏰ 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). (1)
  • GitHub Check: Analyze (java)
🔇 Additional comments (4)
core/src/test/java/com/predic8/membrane/core/kubernetes/GenericYamlParserTest.java (1)

348-351: LGTM!

The empty start() override correctly satisfies the updated BeanRegistry interface contract. For this test stub, no actual lifecycle activation is needed.

annot/src/test/java/com/predic8/membrane/annot/util/YamlParser.java (1)

53-53: LGTM!

The start() call correctly follows the new two-phase lifecycle pattern: first registerBeanDefinitions() to queue events, then start() to process and activate beans before awaiting completion.

annot/src/main/java/com/predic8/membrane/annot/yaml/BeanRegistry.java (1)

26-79: LGTM!

Excellent documentation for the new lifecycle methods. The Javadoc clearly explains thread-safety guarantees, lifecycle expectations, and usage constraints for both registerBeanDefinitions() and start().

README.md (1)

731-744: Inconsistent root element: use api: instead of spec:.

Same inconsistency as above—this example uses spec: while the rest of the document uses api:.

-```yaml -spec: - port: 2000 - flow: +```yaml +api: + port: 2000 + flow:
⛔ Skipped due to learnings
Learnt from: rrayst Repo: membrane/api-gateway PR: 2339 File: distribution/examples/web-services-soap/rest2soap-template/apis.yaml:17-32 Timestamp: 2025-11-23T15:59:51.742Z Learning: In Membrane API Gateway YAML configuration files, response flows execute in reverse order. Steps that appear later in the response flow list actually execute first. For example, if a template references properties and setProperty steps appear after the template in the YAML, those setProperty steps will execute before the template renders. 
private final Map<String, BeanDefinition> bds = new ConcurrentHashMap<>();
private final Set<String> uidsToActivate = ConcurrentHashMap.newKeySet();
private final Map<String, BeanDefinition> bds = new ConcurrentHashMap<>(); // Order is not critical. Order is determined by uidsToActivate
private final List<String> uidsToActivate = new ArrayList<>();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

find . -name "BeanRegistryImplementation.java" 2>/dev/null

Repository: membrane/api-gateway

Length of output: 149


Duplicate UIDs possible in activation list when beans are modified after initial addition.

Changing from Set to List enables deterministic ordering but removes duplicate prevention. The notify() method routes both ADDED and MODIFIED events to handle() (line 188-190), which unconditionally appends UIDs to uidsToActivate (line 180) without checking if already present. If a bean is ADDED then MODIFIED, its UID will appear twice in the list, causing activate() to be called twice during start() (lines 218-219).

Use LinkedHashSet to maintain insertion order while preventing duplicates, or add a duplicate check: if (!uidsToActivate.contains(uid)) uidsToActivate.add(uid);

🤖 Prompt for AI Agents
In annot/src/main/java/com/predic8/membrane/annot/yaml/BeanRegistryImplementation.java around line 44, the uidsToActivate field is a List which allows duplicate UIDs when a bean is ADDED then MODIFIED (notify() routes both to handle() and handle() appends unconditionally), causing activate() to be invoked twice during start(); fix by changing uidsToActivate to a LinkedHashSet to preserve insertion order and prevent duplicates (or, if keeping a List, add a check before adding: only append if not already present), ensuring notify()/handle() logic can remain unchanged and start() will only activate each UID once. 
@predic8 predic8 closed this Dec 8, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants