Implement thread-safe session registry and REST endpoints for Drools sessions (O3-5064)#2
Conversation
Features: - ThreadSafeSessionRegistry with ConcurrentHashMap - 5 new REST endpoints for session management - Auto-startable session support - Session metadata tracking and cleanup - Fixed async execution bug in DroolsSessionController - Backward compatible implementation
|
Thanks so much @UjjawalPrabhat for your contribution! Exciting to see someone else working in the new-ish drools repo. Tagged some experts for review :) |
ibacher
left a comment
There was a problem hiding this comment.
Thanks @UjjawalPrabhat. I think it would better if the overall solution worked a little bit more closely to how the module already works.
I also want to point out that thread-safety is not just a matter of having underlying synchronized data stores. Thread-safety here means that operations in one thread should not be able to interfere with operations in another thread. Usually this means ensuring that only a single-thread can work with a "safely" retrieved instance at a time.
| // register resources | ||
| if (ruleProvider.getRuleResources() != null) { | ||
| ruleProvider.getRuleResources().forEach(kieContainerBuilder::addResource); | ||
| } | ||
| // register session configs |
There was a problem hiding this comment.
Why are you deleting comments?
You're absolutely right. Those comments provide valuable context for understanding the code flow. They were accidentally removed during refactoring. I'll restore all deleted comments.
| @Autowired | ||
| private ThreadSafeSessionRegistry sessionRegistry; | ||
|
|
There was a problem hiding this comment.
Why is this being autowired here?
There was a problem hiding this comment.
Why is this being autowired here?
Initially I thought this was needed for auto-start session registration, but you're correct that this creates unnecessary coupling. After reviewing the auto-start workflow, the registration should happen in DroolsEngineRunner instead, where auto-startable sessions are actually initialized. I'll remove this autowiring.
|
Also, please review our pull request tips which despite its name actually contains rules for how we expect PRs to be put together. |
|
Thank you @ibacher for the comprehensive review! After analyzing all your feedback, I see that several comments point to fundamental architectural issues that require a complete revision: Core Issues Requiring Architectural Changes:
Proposed Solution: try (SessionLease lease = registry.checkOutSession(sessionId, timeout)) { This addresses the Thread1/Thread2 data race scenario you highlighted and provides true thread safety. I'll create a revised implementation addressing all these architectural concerns. Would you prefer I close this PR and create a new one, or update this one with the fixes? Thanks for the thorough review! |
Architectural fixes based on maintainer feedback: ✅ Added SessionLease with per-session locking for exclusive access ✅ Moved auto-start registration to DroolsEngineRunner.run() startup phase ✅ Renamed REST endpoints from /session to /rules per OpenMRS conventions ✅ Changed registerSession() to return boolean instead of throwing ✅ Added Scheduled cleanup with consistent debug logging ✅ Updated usage patterns with try-with-resources pattern ✅ Comprehensive test coverage including concurrency scenarios Prevents Thread1/Thread2 data race issues through check-out mechanism. All 47 tests passing. Addresses all architectural concerns from code review.
cd10e10 to
a090476
Compare
- Restored accidentally deleted comments in registerRuleProvider() - Adjusted cleanup logging levels per maintainer clarification - Addresses final maintainer feedback items
a090476 to
2a46b7d
Compare
|
Thank you @ibacher for the thorough review. All requested changes are now implemented:
Ready for re-review! |
samuelmale
left a comment
There was a problem hiding this comment.
Thank you for working on this @UjjawalPrabhat! My overall concern is scope creep and over-engineering. O3-5064 is basically about implementing a simple registry, which makes it possible to do something like:
if (config.isAutoStart()) {
session = registry.get(sessionId); // retrieve from registry
} else {
session = createNewSession(); // create, use, dispose
}All auto-startable sessions get created and started upon module startup; these are tracked in a session registry which are later accessed on demand in a thread-safe fashion.
If possible, let's come up with the simplest approach to achieve the above. We can later implement concepts like Session Pooling, Scheduled cleanups, etc.
| // Note: Registration moved to DroolsEngineRunner.run() for auto-startable sessions | ||
| // This method now only creates sessions without registering them |
There was a problem hiding this comment.
I think this method should invoke the registry if necessary, ie, if the requested session is auto-startable, we pick the session from the registry.
| * @param sessionId the session identifier | ||
| * @return SimpleObject with existence status | ||
| */ | ||
| @RequestMapping(value = "/rules/{sessionId}/exists", method = RequestMethod.GET) |
There was a problem hiding this comment.
I like the idea of supporting an endpoint used to check if there is an existing session configuration of a specific ID, but I wouldn't restrict this to the registry.
There was a problem hiding this comment.
Do we really need an /exists endpoint? It seems more in line with REST to just GET /rules/{sessionId}, potentially even HEAD /rules/{sessionId} which should respond with a 200 if the sessionId exists and a 404 if it does not.
|
Thank you @samuelmale for the detailed feedback! I completely understand the concern about scope creep and over-engineering. You're absolutely right that the core requirement is a simple registry for auto-startable sessions. I got carried away implementing a comprehensive session management system when the ticket really just needs: Clarifying Questions Before Simplification:
Proposed Simplified Approach:
Happy to implement the simplified version once I have clarity on the above points! |
The registry should be a standalone internal component interfaced via the service.
You've already gone over this with @ibacher, so let's keep it!
The logic for auto-starting (registration) a session can be abstracted by the service, but the entry point for an auto-started session is at module startup.
I think 4 and 5 can be handled in a separate PR. |
- Removed: SessionMetadata, scheduled cleanup, new REST endpoints - Kept: SessionLease check-out pattern, per-session locking, auto-start registration - Tests: 16/16 passing
|
Thank you @samuelmale for the clarifications! I've simplified the implementation to focus on core registry functionality only. Changes Made:Removed (Scope Reduction):
Kept (Core Requirements):
Architecture:The registry now enables the simple pattern you requested: Testing:
Ready for final review! |
- Add service wrapper methods for registry operations - Remove direct registry access from DroolsEngineRunner - Registry now private to DroolsEngineService - All tests passing

Description
This PR implements the solution for OpenMRS issue O3-5064 by reintroducing a thread-safe session registry for Drools KieSession instances and exposing new REST endpoints to query and manage active sessions. All changes maintain backward compatibility and leverage Drools 6+ native thread safety.
Key Changes
This PR fulfills the O3-5064 requirement by restoring REST-based access to Drools sessions in a safe, performant, and maintainable manner.