cdi
cdi copied to clipboard
New Scope SessionCacheScoped
I would like to propose a new scope called @SessionCacheScoped
with an optional cache name. The purpose of the scope is, that data is associated with a session without using the HttpSession
as storage. I often associate some data that I loaded from the database with a user session and using @SessionScoped
is usually fine, but in a clustered setup this becomes a problem due to session replication overhead. To avoid these issue, I would like to put the beans into a local cache instead which is associated with the session.
One might think that this kind of scope should be provided by JCache(JSR 107), but since it is not part of Jakarta EE (yet), I wanted to post it here and maybe start a discussion about the possible inclusion of the JCache API.
The purpose of the scope is, that data is associated with a session without using the HttpSession as storage.
So, would the scope still activate/deactivate based on session creation/timeout? In that case the lifecycle is basically identical to that of session scope but with some simple map backing it instead of HTTP session. Is that correct?
... but in a clustered setup this becomes a problem due to session replication overhead.
I don't see how the new scope you are proposing solves the issue of clustered setup? You will still need to propagate those beans in a cluster because otherwise you break any fail-over scenario. But to do that, you still need to have some replication which gets you back to square one.
I don't know your application, so this may be far fetched, but perhaps you could circumvent some of these issues by either not storing all information within the session bean, or using transient references?
This new scope should be defined in the JCache spec.
So, would the scope still activate/deactivate based on session creation/timeout? In that case the lifecycle is basically identical to that of session scope but with some simple map backing it instead of HTTP session. Is that correct?
Yeah, kind of. The storage would not be a "simple map" but a local JCache cache. The scope would use the bean name + some session identifier as cache key for beans.
I don't see how the new scope you are proposing solves the issue of clustered setup? You will still need to propagate those beans in a cluster because otherwise you break any fail-over scenario. But to do that, you still need to have some replication which gets you back to square one.
It solves the issue, by simply not replicating these beans. These beans in my case are provided through named producers. If a failover happens, it's no big deal if the producer is called again on a different node, as the data is transient. I still would like to associate it with the session though to have the same lifecycle.
It solves the issue, by simply not replicating these beans.
Ok, now I see what you mean.
Yeah, kind of. The storage would not be a "simple map" but a local JCache cache. The scope would use the bean name + some session identifier as cache key for beans.
I am with @mkouba on this - it should land in JCache specification. Just like @Transactional
sits in JTA and @ViewScoped
in JSF.
@mkouba, @manovotn
I am with @mkouba on this - it should land in JCache specification. Just like @Transactional sits in JTA and @ViewScoped in JSF.
Wait. In the sphere of JCache the concept of a "Session" is totally undefined.
@Transactional
sits in JTA because it makes sense that the JTA team defines the semantics of such an annotation.
Should the JCache team define the semantics of an annotation for a web application? Or even do an implementation?
AFAIU JSR107 depends on CDI and CDI defines the session scope. So if JCache defines a scope that relies on that session scope as defined by CDI, this should be fine, no?
AFAIU JSR107 depends on CDI and CDI defines the session scope. So if JCache defines a scope that relies on that session scope as defined by CDI, this should be fine, no?
No it does not. The annotations that are defined in JCache are separate from injection. You can use them in Spring as well.
Also, in my opinion and in retrospective, defining the annotations within the same standard umbrella was a mistake. The annotations did not get much attention and vetting before the standard was released.
@beikov
To avoid these issue, I would like to put the beans into a local cache instead which is associated with the session.
Why are you not just doing this? Just put the stuff into a local cache of your preference and use the session id as key. You only need a standard, where you must interact with the application server. For your purpose the session id seems sufficient.
Let us think not as a performance guy, but as a standard guy:
What does "local" mean w.r.t. the CDI standard?
What would be the guaranteed / expected semantics of a @SessionCacheScoped
annotation?
Answer: There is no local, AFAIK Since a cache may or may not store a value. The semantics would be, on a logic level: A valid implementation may always inject null or do the same as @SessionScoped or anything in between.
To be really useful more needs to be done:
- How to refer to a (local) cache, or, can a cache name/cache reference and cache key be inferred
- Define the concept of a local cache in the caching standard. Right now, in JCache you can basically specify an implementation explicitly or go with one default implementation. If you have the concept "local" and "not-local" you need to address a cache for each purpose in a general way.
- Define how to resolve and configure a cache. JCache does not define how to specify a cache capacity or any external configuration or central cache configuration
For your use case to make sense I guess you are assuming sticky sessions across servers. Is it supposed to be local, only when sticky sessions are used?
Why are you not just doing this? Just put the stuff into a local cache of your preference and use the session id as key. You only need a standard, where you must interact with the application server. For your purpose the session id seems sufficient.
Of course I can implement all of this myself through standard means. I can write a portable extension that adds a context which implements the scope like I described with JCache, but I would prefer if this were something that is provided by the platfrom if possible. Like I wrote, I also wanted to start the discussion about including JCache into Jakarata with this use case.
Currently, I have code like this:
@Produces
@Named("someBean")
@SessionScoped // I want @SessionCacheScoped
public List<SelectItem> getItems() {
// load from database while using some user session attribute
}
If a bean is not available in the cache, the producer would be called to produce it and then put it into the cache. The only way to implement this differently, that I can think of, is to use @RequestScoped
and implement the caching in the method or maybe through an interceptor, although I'm not sure if interceptors are applied to producer methods.
Since a cache may or may not store a value. The semantics would be, on a logic level: A valid implementation may always inject null or do the same as @SessionScoped or anything in between.
Sure, but to be useful it should store the value 😄
How to refer to a (local) cache, or, can a cache name/cache reference and cache key be inferred
My idea was to add an attribute to @SessionCacheScoped(cacheName = "someCache")
and use a default cache if a name is not given.
Define the concept of a local cache in the caching standard. Right now, in JCache you can basically specify an implementation explicitly or go with one default implementation. If you have the concept "local" and "not-local" you need to address a cache for each purpose in a general way.
I thought that JCache was all about "just" local caches and that providers can implement caches as distributed ones as well, but maybe I misread the spec.
Define how to resolve and configure a cache. JCache does not define how to specify a cache capacity or any external configuration or central cache configuration
Resolving of a cache should be done by looking up a Cache by name in the CacheManager. The configuration is a different topic. I usually use Infinispan and configure it through the vendor specific format, but expose the caches through the JCache API. Not sure if JCache really needs to unify cache configuration.
For your use case to make sense I guess you are assuming sticky sessions across servers.
Sticky sessions would reduce the database load, but aren't strictly required.
Is it supposed to be local, only when sticky sessions are used?
This should not matter. It's up to the user to configure the cache. Some maybe want the cache to be just local, others might want cluster invalidations, but that is part of the cache configuration.
What does "local" mean w.r.t. the CDI standard?
Maybe this should be in the Servlet spec, as this is the part that knows specifically about distributed items in the HTTP session. See https://jakarta.ee/specifications/servlet/5.0/jakarta-servlet-spec-5.0.html#distributed-environments
The fact that the current SessionScoped
is in the CDI spec is IMHO a historical mistake. As mentioned above, @transactional
sits in ~~JTA~~ Transactions and @ViewScoped
in ~~JSF~~ Faces.
My idea was to add an attribute to @SessionCacheScoped(cacheName = "someCache") and use a default cache if a name is not given.
Unfortunately scopes can not have attributes officially:
https://jakarta.ee/specifications/cdi/3.0/jakarta-cdi-spec-3.0.html#defining_new_scope_type
(But Faces violates this too, and works everywhere)
Otherwise perhaps @SessionScoped(distributable=false)
could have been an option, together with an addition to the servlet container to mark single items in the session as not distributable.
Well, I guess it depends how you want to use the scope. I'd consider a @SessionScoped
bean, regardless if distributed, not to vanish suddenly because of memory pressure. Whereas a @SessionCacheScoped
bean should IMO have the option be evicted from the backing cache if the JVM is low on memory, but that should be handled by the cache implemention.