-
Notifications
You must be signed in to change notification settings - Fork 6
[NAE-2212] Cluster scope process function caches #363
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: release/7.0.0-rev9
Are you sure you want to change the base?
Changes from all commits
a002636
e6e8dac
6e09ba1
790659b
dd80913
7dc7947
eb56f99
93921f9
cf3dc8c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| package com.netgrif.application.engine.configuration.cache; | ||
|
|
||
| import org.springframework.cache.Cache; | ||
|
|
||
| import java.util.concurrent.Callable; | ||
|
|
||
| public class ReadOnlyCache implements Cache { | ||
|
|
||
| private final Cache cacheDelegate; | ||
|
|
||
| public ReadOnlyCache(Cache cacheDelegate) { | ||
| this.cacheDelegate = cacheDelegate; | ||
| } | ||
|
|
||
| @Override | ||
| public String getName() { return cacheDelegate.getName(); } | ||
|
|
||
| @Override | ||
| public Object getNativeCache() { return cacheDelegate.getNativeCache(); } | ||
|
|
||
| @Override | ||
| public ValueWrapper get(Object key) { return cacheDelegate.get(key); } | ||
|
|
||
| @Override | ||
| public <T> T get(Object key, Class<T> type) { return cacheDelegate.get(key, type); } | ||
|
|
||
| @Override | ||
| public <T> T get(Object key, Callable<T> loader) { return cacheDelegate.get(key, loader); } | ||
|
|
||
| @Override | ||
| public void put(Object key, Object value) { cacheDelegate.put(key, value); } | ||
|
|
||
| @Override | ||
| public void evict(Object key) { | ||
| throw new UnsupportedOperationException("Evict not allowed on worker for " + getName()); | ||
| } | ||
|
|
||
| @Override | ||
| public void clear() { | ||
| throw new UnsupportedOperationException("Clear not allowed on worker for " + getName()); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| package com.netgrif.application.engine.configuration.cache; | ||
|
|
||
| import org.springframework.cache.Cache; | ||
| import org.springframework.cache.concurrent.ConcurrentMapCacheManager; | ||
|
|
||
| import java.util.Objects; | ||
| import java.util.Set; | ||
|
|
||
| public class WorkerConcurrentCacheManager extends ConcurrentMapCacheManager { | ||
| private final Set<String> readOnlyCacheNames; | ||
|
|
||
| public WorkerConcurrentCacheManager() { | ||
| super(); | ||
| this.readOnlyCacheNames = Set.of(); | ||
| } | ||
|
|
||
| public WorkerConcurrentCacheManager(Set<String> readOnlyCacheNames) { | ||
| super(); | ||
| this.readOnlyCacheNames = Set.copyOf( | ||
| Objects.requireNonNull(readOnlyCacheNames, "readOnlyCacheNames must not be null.") | ||
| ); | ||
| } | ||
|
|
||
| public WorkerConcurrentCacheManager(Set<String> readOnlyCacheNames, String... cacheNames) { | ||
| super(cacheNames); | ||
| this.readOnlyCacheNames = Set.copyOf( | ||
| Objects.requireNonNull(readOnlyCacheNames, "readOnlyCacheNames must not be null.") | ||
| ); | ||
| } | ||
|
|
||
| @Override | ||
| protected Cache createConcurrentMapCache(String name) { | ||
| Cache base = super.createConcurrentMapCache(name); | ||
| if (readOnlyCacheNames != null && readOnlyCacheNames.contains(name)) { | ||
| return new ReadOnlyCache(base); | ||
| } | ||
| return base; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -41,6 +41,11 @@ public class CacheConfigurationProperties { | |
| */ | ||
| private String loadedModules = "loadedModules"; | ||
|
|
||
| /** | ||
| * Default cache name for caching namespace functions. | ||
| */ | ||
| private String namespaceFunctions = "namespaceFunctions"; | ||
|
|
||
| /** | ||
| * A list of additional custom cache names. | ||
| * Allows users to define their own cache names for specific use cases. | ||
|
|
@@ -54,7 +59,7 @@ public class CacheConfigurationProperties { | |
| * @return a {@link Set} of all cache names. | ||
| */ | ||
| public Set<String> getAllCaches() { | ||
| Set<String> caches = new LinkedHashSet<>(Arrays.asList(petriNetById, petriNetByIdentifier, petriNetNewest, petriNetCache, loadedModules)); | ||
| Set<String> caches = new LinkedHashSet<>(Arrays.asList(petriNetById, petriNetByIdentifier, petriNetNewest, petriNetCache, loadedModules, namespaceFunctions)); | ||
| caches.addAll(additional); | ||
|
Comment on lines
61
to
63
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major Guard against future drift and blank values If users override Possible follow-up (see proposed constructor in WorkerConcurrentCacheManager and bean wiring in CacheConfiguration). |
||
| return caches; | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -27,5 +27,7 @@ public interface IFieldActionsCacheService { | |||||||||||||||||||
|
|
||||||||||||||||||||
| void clearNamespaceFunctionCache(); | ||||||||||||||||||||
|
|
||||||||||||||||||||
| void cacheAllPetriNetsFunctions(); | ||||||||||||||||||||
|
|
||||||||||||||||||||
|
Comment on lines
+30
to
+31
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Define the contract (scope, version, and cache semantics) for the new bulk method. Please document whether this:
Consider a tighter name for consistency with the singular: cacheAllPetriNetFunctions(). Apply this diff to add Javadoc: - void cacheAllPetriNetsFunctions();
+ /**
+ * Pre-populates the namespace function cache for all PetriNets.
+ * Contract:
+ * - Only newest version per PetriNet identifier SHOULD be cached.
+ * - Stale cache entries for non-existing PetriNets SHOULD be cleared or overwritten.
+ * - This operation MAY be long-running; invoke off request threads.
+ */
+ void cacheAllPetriNetsFunctions();📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||
| void clearFunctionCache(); | ||||||||||||||||||||
| } | ||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Verify
ReadOnlyCachecorrectly prevents all write operations.The wrapper logic correctly delegates wrapping to
ReadOnlyCachefor caches in the read-only set. Ensure thatReadOnlyCacheproperly blocks all mutating operations (put,evict,clear, etc.) to maintain the read-only guarantee.Run the following script to examine the
ReadOnlyCacheimplementation:🏁 Script executed:
Length of output: 913
🏁 Script executed:
Length of output: 1198
🏁 Script executed:
Length of output: 0
Enforce read-only behavior by blocking all mutating cache operations in ReadOnlyCache
ReadOnlyCache currently delegates put(Object,Object) and inherits default putIfAbsent(Object,Object), so write operations still succeed. Override both methods to throw UnsupportedOperationException to uphold the read-only guarantee.
File: application-engine/src/main/java/com/netgrif/application/engine/configuration/cache/ReadOnlyCache.java
🤖 Prompt for AI Agents