[
https://issues.jboss.org/browse/WFLY-11489?page=com.atlassian.jira.plugin...
]
Richard Achmatowicz edited comment on WFLY-11489 at 1/11/19 1:39 PM:
---------------------------------------------------------------------
I've now had a look in detail at the affinity processing here and have an idea for a
fix. There are three problems to overcome.
The first is to correct the assignment of strong and weak affinity for the SFSB with
passivationEnabled == false. If the initial affinity of the proxy before session creation
is (strong affinity, weak affinity) = (NONE, NONE), which is the default, then the
affinity assignment we expect is either (NODE, NONE) or (NONE, NODE) which are equivalent.
In other words, invocations should be tied to the node that the session is created on.
This will require simple changes to the way the affinity is calculated - namely using the
session cache do to the calculations.
The second problem is that the v3 protocol will not allow sending arbitrary affinity
values back to the client: it is assumed that:
* updates to strong affinity are always of type ClusterAffinity
* updates to weak affinity are always of type NodeAffinity
For the code, see for example
https://github.com/wildfly/jboss-ejb-client/blob/master/src/main/java/org...
This means that we can't assign (NODE, NONE) to the SFSB with
passivationEnabled=false, but we can assign (NONE, NODE) which is equivalent. This seems
to be the only way around this particular issue.
The third problem is that, on the client side, when the reply from the server is unpacked,
there are some adjustments made to the affinity values before the invocation completes.
These adjustments seem to interpret Affinity.NONE as "the affinity is not set",
and try to replace Affinity.NONE with the targetAffinity which was determined when doing
discovery. For example:
https://github.com/wildfly/jboss-ejb-client/blob/master/src/main/java/org....
In fact, Affinity.NONE means "I don't care which node you send me to" and
does not mean "the affinity is not set". So, for example, the affinity
adjustment made in the DiscoveryEJBClientInterceptor above will transform (NONE, NODE)
into (NODE, NODE) or possibly (URI, NODE) where URI is a URIAffinity assigment for the
locator pointing to the server used to create the session. In this case, such a
manipulation may not hurt, but it seems to be unnecessary.
So, i'll be putting together a fix which incorporates these three changes. It would
have been much easier and cleaner to be able to assign to the strong or weak affinity any
affinity type, but with the v3 protocol, that is currently not possible.
PS For those interested, targetAffinity is assigned as a side effect when we choose a
target for the invocation. Doing discovery results in choosing a serviceURL to send the
invocation to which satisfies the strong/weak affinity constraints. That serviceURL
contains a location together with optional node, module and cluster attributes. The
location tells us how to connect to the node, the attributes tell us what the node name
is, which modules are deployed there and which clusters it belongs to. targetAffinity is
NodeAffinity(<node name>) if the serviceURL does have a node attribute, and
URIAffinity(<location>) if there is no node attribute. It seems to be used to make
adjustments to affinity on the client based on where the last invocation attempt went.
I'm really not seeing why this is needed.
was (Author: rachmato):
I've now had a look in detail at the affinity processing here and have an idea for a
fix. There are three problems to overcome.
The first is to correct the assignment of strong and weak affinity for the SFSB with
passivationEnabled == false. If the initial affinity of the proxy before session creation
is (strong affinity, weak affinity) = (NONE, NONE), which is the default, then the
affinity assignment we expect is either (NODE, NONE) or (NONE, NODE) which are equivalent.
In other words, invocations should be tied to the node that the session is created on.
This will require simple changes to the way the affinity is calculated - namely using the
session cache do to the calculations.
The second problem is that the v3 protocol will not allow sending arbitrary values
affinity back to the client: it is assumed that:
* updates to strong affinity are always of type ClusterAffinity
* updates to weak affinity are always of type NodeAffinity
For the code, see for example
https://github.com/wildfly/jboss-ejb-client/blob/master/src/main/java/org...
This means that we can't assign (NODE, NONE) to the SFSB with
passivationEnabled=false, but we can assign (NONE, NODE) which is equivalent. This seems
to be the only way around this particular issue.
The third problem is that, on the client side, when the reply from the server is unpacked,
there are some adjustments made to the affinity values before the invocation completes.
These adjustments seem to interpret Affinity.NONE as "the affinity is not set",
and try to replace Affinity.NONE with the targetAffinity which was determined when doing
discovery. For example:
https://github.com/wildfly/jboss-ejb-client/blob/master/src/main/java/org....
In fact, Affinity.NONE means "I don't care which node you send me to" and
does not mean "the affinity is not set". So, for example, the affinity
adjustment made in the DiscoveryEJBClientInterceptor above will transform (NONE, NODE)
into (NODE, NODE) or possibly (URI, NODE) where URI is a URIAffinity assigment for the
locator pointing to the server used to create the session. In this case, such a
manipulation may not hurt, but it seems to be unnecessary.
So, i'll be putting together a fix which incorporates these three changes. It would
have been much easier and cleaner to be able to assign to the strong or weak affinity any
affinity type, but with the v3 protocol, that is currently not possible.
PS For those interested, targetAffinity is assigned as a side effect when we choose a
target for the invocation. Doing discovery results in choosing a serviceURL to send the
invocation to which satisfies the strong/weak affinity constraints. That serviceURL
contains a location together with optional node, module and cluster attributes. The
location tells us how to connect to the node, the attributes tell us what the node name
is, which modules are deployed there and which clusters it belongs to. targetAffinity is
NodeAffinity(<node name>) if the serviceURL does have a node attribute, and
URIAffinity(<location>) if there is no node attribute. It seems to be used to make
adjustments to affinity on the client based on where the last invocation attempt went.
I'm really not seeing why this is needed.
SFSB not sticky on a single cluster node when clustering of the bean
is disabled
--------------------------------------------------------------------------------
Key: WFLY-11489
URL:
https://issues.jboss.org/browse/WFLY-11489
Project: WildFly
Issue Type: Bug
Components: Clustering, Remoting
Affects Versions: 15.0.0.Final
Environment: A clustered environment with 2 nodes. Both nodes started with an
unmodified {{standalone-ha.xml}} configuration (see _Steps to Reproduce_)
This issue happens on 15.0.0.Final and was tested as well as on current head (sha:
372697282dccefd0b9df48e6aa4dcb69e1c4b40f).
Reporter: Jörg Bäsner
Assignee: Richard Achmatowicz
Priority: Major
Attachments: reproducer.zip
In case a stateful session bean is annotated with:
{{@Stateful(passivationCapable=false)}}
then the serialization is *disabled* and thus the bean is only available on a single
cluster node.
When a client now calls two different methods on this stateful bean it intermittently
ends up on different cluster nodes, resulting in the following Exception:
{code}
ERROR [org.jboss.as.ejb3.invocation] (default task-2) WFLYEJB0034: EJB Invocation failed
on component TestSessionEJB for method public abstract void
test.ITestSession.method2(java.lang.String,java.lang.String) throws
javax.ejb.EJBException,java.rmi.RemoteException: javax.ejb.NoSuchEJBException:
WFLYEJB0168: Could not find EJB with id UUIDSessionID
[4b0f4a27-40ba-411b-8852-0108a5ec64f4]
at
org.jboss.as.ejb3.component.stateful.StatefulComponentInstanceInterceptor.processInvocation(StatefulComponentInstanceInterceptor.java:55)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at
org.jboss.as.ejb3.component.interceptors.AdditionalSetupInterceptor.processInvocation(AdditionalSetupInterceptor.java:54)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at
org.jboss.invocation.InterceptorContext$Invocation.proceed(InterceptorContext.java:509)
at
org.jboss.weld.module.ejb.AbstractEJBRequestScopeActivationInterceptor.aroundInvoke(AbstractEJBRequestScopeActivationInterceptor.java:81)
at
org.jboss.as.weld.ejb.EjbRequestScopeActivationInterceptor.processInvocation(EjbRequestScopeActivationInterceptor.java:89)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at
org.jboss.as.ejb3.component.interceptors.CurrentInvocationContextInterceptor.processInvocation(CurrentInvocationContextInterceptor.java:41)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at
org.jboss.as.ejb3.component.invocationmetrics.WaitTimeInterceptor.processInvocation(WaitTimeInterceptor.java:47)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at
org.jboss.as.ejb3.security.SecurityContextInterceptor.processInvocation(SecurityContextInterceptor.java:100)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at
org.jboss.as.ejb3.deployment.processors.StartupAwaitInterceptor.processInvocation(StartupAwaitInterceptor.java:22)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at
org.jboss.as.ejb3.component.interceptors.ShutDownInterceptorFactory$1.processInvocation(ShutDownInterceptorFactory.java:64)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at
org.jboss.as.ejb3.deployment.processors.EjbSuspendInterceptor.processInvocation(EjbSuspendInterceptor.java:57)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at
org.jboss.as.ejb3.component.interceptors.LoggingInterceptor.processInvocation(LoggingInterceptor.java:67)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at
org.jboss.as.ee.component.NamespaceContextInterceptor.processInvocation(NamespaceContextInterceptor.java:50)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at
org.jboss.invocation.ContextClassLoaderInterceptor.processInvocation(ContextClassLoaderInterceptor.java:60)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at org.jboss.invocation.InterceptorContext.run(InterceptorContext.java:438)
at
org.wildfly.security.manager.WildFlySecurityManager.doChecked(WildFlySecurityManager.java:618)
at
org.jboss.invocation.AccessCheckingInterceptor.processInvocation(AccessCheckingInterceptor.java:57)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at
org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:53)
at org.jboss.as.ee.component.ViewService$View.invoke(ViewService.java:198)
at
org.wildfly.security.auth.server.SecurityIdentity.runAsFunctionEx(SecurityIdentity.java:406)
at
org.jboss.as.ejb3.remote.AssociationImpl.invokeWithIdentity(AssociationImpl.java:565)
at org.jboss.as.ejb3.remote.AssociationImpl.invokeMethod(AssociationImpl.java:546)
at
org.jboss.as.ejb3.remote.AssociationImpl.lambda$receiveInvocationRequest$0(AssociationImpl.java:197)
at
org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1985)
at
org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1487)
at
org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1349)
at java.lang.Thread.run(Thread.java:748)
{code}
--
This message was sent by Atlassian Jira
(v7.12.1#712002)