I've been experimenting with a modified version of TWVSP, using chained planning variables and anchors. Similar approach as the TWVSP example with Standstill.
It looks like this:
Vehicle1 (AnchorShadowVarialbe) - Trip1_1 - Trip1_2 - ... - Trip1_k1
...
VehicleM (Anchor) - TripM_1 - TripM_2 - ... - TripM_kM
Trips are assigned to vehicles. Each trip has a start/end timestamp. One vehicle cannot service 2 trips that are overlapping.
To speed up the solver, I started splitting the search space into partitions with a SolutionPartitioner implementation, since the trips could be grouped into clusters based on their timeframes. The goal is to get trip-vehicle assignments for the clusters, but I have one vehicle fleet.
First issue, that I can't use the same vehicle objects, because the solver will fail with IllegalStateException - which is fine, I clone the list of vehicles for each partition and assign to trips to those cloned objects.
Then, I catch the phaseEnded event where phaseScope is an instance of PartitionedSearchPhaseScope (ie partition search ended event) and reassign the trips to the original vehicle objects (making sure that pointers are pointing to the same objects in each direction (similar to previousStandstill, nextVisit form the example)), as well as manually fix the chains, so cluster-chains are anchored only to the original vehicle, and they are chained together:
vehicleX - (partition0.trip(0)) - ... - (partition(i-1).trip(last)) - (partition(i).trip(0)) - ...
Then I update the solution in the solution scope:
partitionPhaseScope.getSolverScope().setBestSolution(mergedSolution);
I want to do a local search after the partitioned one, as it's advised in the docs, but get an error:
Caused by: java.lang.IllegalStateException: The move thread with moveThreadIndex (65) has thrown an exception. Relayed here in the parent thread.
at org.optaplanner.core.impl.heuristic.thread.OrderByMoveIndexBlockingQueue.take(OrderByMoveIndexBlockingQueue.java:147)
at org.optaplanner.core.impl.localsearch.decider.MultiThreadedLocalSearchDecider.forageResult(MultiThreadedLocalSearchDecider.java:188)
at org.optaplanner.core.impl.localsearch.decider.MultiThreadedLocalSearchDecider.decideNextStep(MultiThreadedLocalSearchDecider.java:159)
at org.optaplanner.core.impl.localsearch.DefaultLocalSearchPhase.solve(DefaultLocalSearchPhase.java:71)
at org.optaplanner.core.impl.solver.AbstractSolver.runPhases(AbstractSolver.java:99)
at org.optaplanner.core.impl.solver.DefaultSolver.solve(DefaultSolver.java:189)
at com.mynamespace.planner.v4.rest.ScheduleResource.startSolving(ScheduleResource.java:221)
at com.mynamespace.planner.v4.rest.ScheduleResource.solve(ScheduleResource.java:112)
at com.mynamespace.planner.v4.rest.ScheduleResource_ClientProxy.solve(ScheduleResource_ClientProxy.zig:156)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:167)
at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:130)
at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:638)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:504)
at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$2(ResourceMethodInvoker.java:454)
at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:456)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:417)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:391)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:68)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:488)
... 49 more
Caused by: java.lang.NullPointerException
at org.drools.core.common.NamedEntryPoint.update(NamedEntryPoint.java:353)
at org.drools.core.common.NamedEntryPoint.update(NamedEntryPoint.java:338)
at org.drools.core.impl.StatefulKnowledgeSessionImpl.update(StatefulKnowledgeSessionImpl.java:1587)
at org.drools.core.impl.StatefulKnowledgeSessionImpl.update(StatefulKnowledgeSessionImpl.java:1559)
at org.optaplanner.core.impl.score.stream.drools.DroolsConstraintSession.update(DroolsConstraintSession.java:47)
at org.optaplanner.core.impl.score.director.stream.ConstraintStreamScoreDirector.afterVariableChanged(ConstraintStreamScoreDirector.java:141)
at org.optaplanner.core.impl.domain.variable.inverserelation.SingletonInverseVariableListener.retract(SingletonInverseVariableListener.java:96)
at org.optaplanner.core.impl.domain.variable.inverserelation.SingletonInverseVariableListener.beforeVariableChanged(SingletonInverseVariableListener.java:46)
at org.optaplanner.core.impl.domain.variable.listener.support.VariableListenerSupport.beforeVariableChanged(VariableListenerSupport.java:174)
at org.optaplanner.core.impl.score.director.AbstractScoreDirector.beforeVariableChanged(AbstractScoreDirector.java:433)
at org.optaplanner.core.impl.score.director.AbstractScoreDirector.changeVariableFacade(AbstractScoreDirector.java:446)
at org.optaplanner.core.impl.heuristic.selector.move.generic.chained.ChainedChangeMove.doMoveOnGenuineVariables(ChainedChangeMove.java:74)
at org.optaplanner.core.impl.heuristic.move.AbstractMove.doMove(AbstractMove.java:36)
at org.optaplanner.core.impl.heuristic.move.AbstractMove.doMove(AbstractMove.java:31)
at org.optaplanner.core.impl.score.director.AbstractScoreDirector.doAndProcessMove(AbstractScoreDirector.java:178)
at org.optaplanner.core.impl.heuristic.thread.MoveThreadRunner.run(MoveThreadRunner.java:146)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
Any ideas what's missing?
Is there any docs on how to do PartitionedSearch with chained planning variables?
Thanks.
The FactHandle is probably null, so at the very least, the error message should be improved: https://issues.redhat.com/browse/PLANNER-2222
As for the actual bug, your Partitioned probably creates a partition that doesn't have that fact in it's #ProblemFactCollectionProperty or #PlanningEntityCollectionProperty, but does have it in a chained entity's trailing chain (= think variable listeners for arrival time etc that "update" it).
Related
We have an application running on a Wildfly 17. I have a scenario, which occurs occasionally, in which two background threads are accessing the same entity:
Thread A deletes the entity (for good reason)
Thread B is working on slightly older data and attempts to update the entity
When thread B is the later of the two, it fails due to the concurrent modification. This works correctly. It is retried automatically and finds that nothing needs to be done anymore (because the entity has been deleted). That is the intended behavior, when these two threads collide. All is fine!
However I find that this is logged as ERROR by CMTTxInterceptor:
2020-03-31 16:51:35,463 +0200 ERROR: as.ejb3.invocation - WFLYEJB0034: EJB Invocation failed on component ... for method ... throws ...:
javax.ejb.EJBTransactionRolledbackException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
at org.jboss.as.ejb3.tx.CMTTxInterceptor.invokeInCallerTx(CMTTxInterceptor.java:203) [wildfly-ejb3-17.0.1.Final.jar:17.0.1.Final]
at org.jboss.as.ejb3.tx.CMTTxInterceptor.required(CMTTxInterceptor.java:364) [wildfly-ejb3-17.0.1.Final.jar:17.0.1.Final]
at org.jboss.as.ejb3.tx.CMTTxInterceptor.processInvocation(CMTTxInterceptor.java:144) [wildfly-ejb3-17.0.1.Final.jar:17.0.1.Final]
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
...
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [rt.jar:1.8.0_171]
at org.apache.activemq.artemis.utils.ActiveMQThreadFactory$1.run(ActiveMQThreadFactory.java:118)
Caused by: javax.persistence.OptimisticLockException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.wrapStaleStateException(AbstractEntityManagerImpl.java:1729) [hibernate-entitymanager.jar:5.0.12.Final]
... at org.jboss.as.ejb3.tx.CMTTxInterceptor.invokeInCallerTx(CMTTxInterceptor.java:185) [wildfly-ejb3-17.0.1.Final.jar:17.0.1.Final]
... 262 more
Caused by: org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
at org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:67) [hibernate-core.jar:5.0.12.Final]
at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:54) [hibernate-core.jar:5.0.12.Final]
at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:46) [hibernate-core.jar:5.0.12.Final]
at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:3261) [hibernate-core.jar:5.0.12.Final]
...
It seems to me, that this log is incorrect, mostly because this is not an ERROR. Concurrent modification is something normal, that is to be expected - and that our application logic handles. This log will distract my colleagues at the hotline.
Do you agree that the logging is incorrect, or am I missing something?
I think I will disable logging for "as.ejb3.invocation".
In your case this exception was thrown because Hibernate detected that the entity previously fetched from database was changed (deleted) during the current transaction. So, there is nothing to update.
In this specific case I think you can ignore or swallow the exception. In other cases, it may be good to know about this exception, so I recommend swallow the exception but don’t disable as a whole on log level.
What I actually wanted to do is to have a Drools rule as so:
rule "globalRequiredPredecessorAfterMe"
when
$rpAll: Set(size>1) from accumulate (
Customer(vehicle!= null, vehicle.vehicleTyp != VehicleTyp.DUMMY, $rpAfterMe: requiredPredecessorsAfterMe);
collectSet($rpAfterMe)
)
then
scoreHolder.addMediumConstraintMatch(kcontext, - $rpAll.size()-1);
end
Unfortunately, on the second move in CH drools awards me with a
Exception in thread "main" java.lang.RuntimeException: java.lang.NullPointerException
at org.drools.core.rule.SingleAccumulate.reverse(SingleAccumulate.java:124)
...
Is this a feature?
I swallowed my pride and to wrote a fantastically complex Listener which is supposed to to what the Drools rule above did. With an assertionScoreDirectorFactory (an EasyScoreCalculator) I get score corruption. On a closer look, I get a corruption in one of the two cases:
My planning entity's previousXXX is set exactly to the same value
An Undo move is done
To investigate, I set the solution to the state just before the score corruption occurs. I use the CreateChangeMoves from Optaplanner's 7.4.1.Final SolutionBusiness class. (On a side note, it would be really helpful if one could also set a MoveCountLimit in the SolverConfig.)
So I create the scoreDirector as follows
SolverFactory<MySolution> solverFactory = SolverFactory.createFromXmlResource(
SolverConfigXML);
solver = solverFactory.buildSolver();
ScoreDirectorFactory<MySolution> scoreDirectorFactory = solver.getScoreDirectorFactory();
scoreDirector = scoreDirectorFactory.buildScoreDirector();
scoreDirector.setWorkingSolution(unsolvedSolution);
within a JUnit 5 test and then perform several ChangeMoves to mimick the solution just before the offending move occurs. However, when I perform the offending move as in bullet 1 above,
// customer SUK0002030's previousVehicleOrCustomer is DUMMY_3
cm = createChangeMove(nameToCustomerMap.get("SUK0002030"), "previousVehicleOrCustomer", nameToVehicleMap.get("DUMMY_3"));
cm.doMove(scoreDirector);
I get a
java.lang.IllegalStateException: The entity (SUK0002030) has a variable (previousVehicleOrCustomer) with value (DUMMY_3) which has a sourceVariableName variable (nextCustomer) with a value (null) which is not that entity.
Verify the consistency of your input problem for that sourceVariableName variable.
at org.optaplanner.core.impl.domain.variable.inverserelation.SingletonInverseVariableListener.retract(SingletonInverseVariableListener.java:87)
...
When I set the previousVehicleOrCustomer to null, and then back to DUMMY_3, everything is fine and no score corruption occurs.
Similarly, when attempting to create an (offending) UndoMove of the previous Move cm, bullet 2 above, as so
cm.createUndoMove(scoreDirector).doMove(scoreDirector)
I get the same message:
java.lang.IllegalStateException: The entity (SUK0002014) has a variable (previousVehicleOrCustomer) with value (Vehicle_0) which has a sourceVariableName variable (nextCustomer) with a value (null) which is not that entity.
Verify the consistency of your input problem for that sourceVariableName variable.
at org.optaplanner.core.impl.domain.variable.inverserelation.SingletonInverseVariableListener.retract(SingletonInverseVariableListener.java:87)
...
Of course, if I manually create the UndoMove (by simply setting the previousVehicleOrCustomer back to null), everything is fine.
These moves really should be possible and I'm really curious to find out what's wrong.
I am getting following exception in a single box cq5 author environment.
javax.jcr.InvalidItemStateException: Item cannot be saved
because node property has been modified externally
more exception details:
Caused by: javax.jcr.InvalidItemStateException: Unable to update a stale item: item.save()
at org.apache.jackrabbit.core.ItemSaveOperation.perform(ItemSaveOperation.java:262)
at org.apache.jackrabbit.core.session.SessionState.perform(SessionState.java:216)
at org.apache.jackrabbit.core.ItemImpl.perform(ItemImpl.java:91)
at org.apache.jackrabbit.core.ItemImpl.save(ItemImpl.java:329)
at org.apache.jackrabbit.core.session.SessionSaveOperation.perform(SessionSaveOperation.java:65)
at org.apache.jackrabbit.core.session.SessionState.perform(SessionState.java:216)
at org.apache.jackrabbit.core.SessionImpl.perform(SessionImpl.java:361)
at org.apache.jackrabbit.core.SessionImpl.save(SessionImpl.java:812)
at com.day.crx.core.CRXSessionImpl.save(CRXSessionImpl.java:142)
at org.apache.sling.jcr.resource.internal.helper.jcr.JcrResourceProvider.commit(JcrResourceProvider.java:511)
... 215 more
Caused by: org.apache.jackrabbit.core.state.StaleItemStateException: 3bec1cb7-9276-4bed-a24e-0f41bb3cf5b7/{}ssn has been modified externally
at org.apache.jackrabbit.core.state.SharedItemStateManager$Update.begin(SharedItemStateManager.java:679)
at org.apache.jackrabbit.core.state.SharedItemStateManager.beginUpdate(SharedItemStateManager.java:1507)
at org.apache.jackrabbit.core.state.SharedItemStateManager.update(SharedItemStateManager.java:1537)
at org.apache.jackrabbit.core.state.LocalItemStateManager.update(LocalItemStateManager.java:400)
at org.apache.jackrabbit.core.state.XAItemStateManager.update(XAItemStateManager.java:354)
at org.apache.jackrabbit.core.state.LocalItemStateManager.update(LocalItemStateManager.java:375)
at org.apache.jackrabbit.core.state.SessionItemStateManager.update(SessionItemStateManager.java:275)
at org.apache.jackrabbit.core.ItemSaveOperation.perform(ItemSaveOperation.java:258)
Here is the code sample:
adminResourceResolver = resourceResolverFactory
.getAdministrativeResourceResolver(null);
Resource fundPageResource = adminResourceResolver.getResource(page
.getPath() + "/jcr:content");
ModifiableValueMap homePageResourceProperties = fundPageResource
.adaptTo(ModifiableValueMap.class);
homePageResourceProperties.put("ssn",(person.getSsn());
adminResourceResolver.commit();
Any ideas ? It could be possible multiple threads accessing this code, as multiple authors on multiple pages calling this code from a authored component.
Thank you,
Sri
This is an error your see often in CQ5.5 (and lessens with each version upwards). The root cause of this issue is that multiple processes/services are modifying the same resource in roughly the same timespan (usually using different sessions, sometimes even with different users).
A small example to demonstrate perhaps. Session A and B both have a reference to Resource X. Session A modifies some properties on X, saves and commits, and is destroyed. This all goes smoothly. Session B still has a snapshot of the situation before A made modifications, session B makes modifications and all seems well UNTIL it tries to save. At this point, session B detects that it can't commit its changes because it doesn't have the latest node state. It has detected some other sessions made changes to the same node. In essence the current node state conflicts with modifications that session A has done and throws an ItemStale exception. The reason for this exception is the notion that the API doesn't know wether you want to keep the changes made by A, keep the changes made by the current session and discard the changes made by A, or merge them.
This error happens often with long running sessions and with workflow/listener combinations. Therefore the recommendation is to keep sessions as short as possible to prevent this kind of conflicts as much as possible.
One way to deal with this is to call session.refresh(keepChangesBoolean) before calling .save(). This instructs the current session to check for updates made by other sessions and deal with it according to the boolean flag you submit. This however is not a guarantee as it's still possible that between your refresh and your save call, yet another session has done the same. It only lowers the odds of this exception occurring.
Another way to deal with this is to retry again from scratch.
We have an application which was working fine as a monolith.
Now we are in the process of splitting the application
In this process, I am getting an error stating something as shown here below...
This happens only at the place of d.close()
Document d = new Document(PageSize.A4, 10, 10, 50, 50);
......
.....
finally{
if(d.isOpen()) {
d.close();
}
byteOutputStream.flush();
byteOutputStream.close();
pw.close();
return byteOutputStream.toByteArray();
}
(As a monolith the whole application was working fine)
(iText2.1.7 jar is used)
at com.ibm.CORBA.iiop.UtilDelegateImpl.mapSystemException(UtilDelegateImpl.java:241)
at javax.rmi.CORBA.Util.mapSystemException(Util.java:84)
at <<stub path>>.retrieve(_fileName1Remote_Stub.java:1)
at <<filePath>>.retrieve(fileName2.java:778)
at <<filePath>>.onCustomAction1(fileName3.java:403)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:60)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
at java.lang.reflect.Method.invoke(Method.java:611)
at org.apache.el.parser.AstValue.invoke(AstValue.java:266)
at org.apache.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:278)
at org.apache.myfaces.view.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:83)
at javax.faces.event.MethodExpressionActionListener.processAction(MethodExpressionActionListener.java:83)
... 43 more
Caused by: com.itextpdf.text.exceptions.IllegalPdfSyntaxException: Unbalanced save/restore state operators.
at com.itextpdf.text.pdf.PdfContentByte.sanityCheck(PdfContentByte.java:3171)
at com.itextpdf.text.pdf.PdfContentByte.toPdf(PdfContentByte.java:245)
at com.itextpdf.text.pdf.PdfFormXObject.(PdfFormXObject.java:88)
at com.itextpdf.text.pdf.PdfTemplate.getFormXObject(PdfTemplate.java:241)
at com.itextpdf.text.pdf.PdfWriter.addSharedObjectsToBody(PdfWriter.java:1257)
at com.itextpdf.text.pdf.PdfWriter.close(PdfWriter.java:1169)
at com.itextpdf.text.pdf.PdfDocument.close(PdfDocument.java:780)
at com.itextpdf.text.Document.close(Document.java:409)
at <>.createPDF(<>.java:135)
at <>.getPdfData(fileName1Bean.java:339)
at <>.retrieve(fileName1Bean.java:205)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:88)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:55)
at java.lang.reflect.Method.invoke(Method.java:613)
at com.ibm.ejs.container.EJSContainer.invokeProceed(EJSContainer.java:5730)
at com.ibm.ejs.container.interceptors.InvocationContextImpl.proceed(InvocationContextImpl.java:568)
at <>.retrieveIntercept(<>.java:43)
at sun.reflect.GeneratedMethodAccessor215.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:55)
at java.lang.reflect.Method.invoke(Method.java:613)
at com.ibm.ejs.container.interceptors.InterceptorProxy.invokeInterceptor(InterceptorProxy.java:227)
at com.ibm.ejs.container.interceptors.InvocationContextImpl.proceed(InvocationContextImpl.java:548)
at com.ibm.ejs.container.interceptors.InvocationContextImpl.doAroundInvoke(InvocationContextImpl.java:229)
at com.ibm.ejs.container.EJSContainer.invoke(EJSContainer.java:5621)
at <>_c01dfd09.retrieve(EJSRemote0SL<>Bean_c01dfd09.java)
at <>Bean_c01dfd09_Tie.retrieve(_<>Bean_c01dfd09_Tie.java:1)
at <>.invoke(<>_c01dfd09_Tie.java)
at com.ibm.CORBA.iiop.ServerDelegate.dispatchInvokeHandler(ServerDelegate.java:669)
at com.ibm.CORBA.iiop.ServerDelegate.dispatch(ServerDelegate.java:523)
at com.ibm.rmi.iiop.ORB.process(ORB.java:523)
at com.ibm.CORBA.iiop.ORB.process(ORB.java:1575)
at com.ibm.rmi.iiop.Connection.doRequestWork(Connection.java:3039)
at com.ibm.rmi.iiop.Connection.doWork(Connection.java:2922)
at com.ibm.rmi.iiop.WorkUnitImpl.doWork(WorkUnitImpl.java:64)
at com.ibm.ws.giop.threadpool.WorkQueueElement.dispatch(WorkQueueElement.java:165)
at com.ibm.ws.giop.filter.GiopFilterChain.processMessage(GiopFilterChain.java:203)
at com.ibm.ws.giop.threadpool.PooledThread.handleRequest(PooledThread.java:81)
at com.ibm.ws.giop.threadpool.PooledThread.run(PooledThread.java:102)
at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1862)
So here it is...
First of all, I apologize if there was ambiguity in my question.
As said, version 2.1.7 is also used (thanks to the point made by Amedee). There is a 5.x version which I found in the shared libraries of the server.
Since the directory structure is totally different between the two versions, both the jars are maintained for a specific reason.
Also, I am new to this whole application myself and trying to get an understanding with people around in this project. When people who developed it may not be here, I thought a post may give me some idea. So, you are also partly correct Mr.Lowagie - I am ignorant on iText and doing my learning as well - I do not have a reason to Lie! :-).
Mkl, there is no exception in the try block. What eventually turned out was that the image was not getting generated or getting garbled for some other reasons. And it is being investigated. I have given this activity to a person who understands the system better than I do.
Thanks to all your mails and support my dear friends!
I have a strange issue (hope you can help): I am working on a GWT Web Application that has times when more than 4 - 5 GWT RPC calls are made in the same time - as far as time is concerned.
Every once in a while - once every 15 calls maybe? The return Object from one call, gets 'assigned' to another. I have proof of this by using the gwt-log library on the client side.
Here the return object of the HistoryChangesCount call, got assigned to the modelingGetTemplates call also.
Thus resulting in a ClassCastException in the client file that made the call, on the same line as the onSuccess method.
Do you have any tips on how I can avoid this?
PS - I log every response object.toString() on error level. I know it's not best practice. It's just for troubleshooting.
[14:38:01.026] "(-:-) 2014-04-03 14:38:01,025 [ERROR] getHistoryChangesCount - HistoryPreviewFacet - SUCCESS RETURNED: HistoryChangesCount{dateToNumberOfChangesMap={Mon Mar 31 03:00:00 GMT+300 2014=3}, lastUpdatedOn=Mon Mar 31 11:11:02 GMT+300 2014}
"
[14:38:01.163] "(-:-) 2014-04-03 14:38:01,162 [ERROR] modelingGetTemplates - ModelingTemplatesDropdown - SUCCESS RETURNED: HistoryChangesCount{dateToNumberOfChangesMap={Mon Mar 31 03:00:00 GMT+300 2014=3}, lastUpdatedOn=Mon Mar 31 11:11:02 GMT+300 2014}
"
[14:38:01.175] "(-:-) 2014-04-03 14:38:01,174 [ERROR] Browser: null
java.lang.ClassCastException
at Unknown.iCb(StackTraceCreator.java:174)
at Unknown.sd(StackTraceCreator.java:508)
at Unknown.Txn(Throwable.java:46)
at Unknown.kIc(Cast.java:46)
at Unknown.rff(ModelingTemplatesDropdown.java:79)
at Unknown.bXi(AsyncWrapperForRPCManager.java:38)
at Unknown.Loe(RequestCallbackAdapter.java:232)
at Unknown.MWb(Request.java:258)
at Unknown.qXb(RequestBuilder.java:412)
at Unknown.anonymous(XMLHttpRequest.java:351)
at Unknown.eBb(Impl.java:189)
at Unknown.hBb(Impl.java:242)
at Unknown.anonymous(Impl.java:70)
"
Here is how a successful call to modelingGetTemplates looks like:
[14:37:24.933] "(-:-) 2014-04-03 14:37:24,932 [ERROR] modelingGetTemplates - ModelingTemplatesDropdown - SUCCESS RETURNED: [Advanced Business Application, Advanced Business Transaction, TestTemplate]
"
I am using vanilla GWT-RPC. I only have a class that extends AsyncWrapper for logging. I also created myself a client side queue that limits the number of parallel calls to 4, but even so it still happens.
Versions:
GWT: 2.5.1
and I also use Sencha GXT, not sure if relevant.
Here is a video of the issue reproducing - at 0:30 - this time another call get's the object from modelingGetTemplates.
The end result is that my widget is stuck on loading waiting for data forever. And of course angry users :)
Documenting the way I got around this, rather than fixing it :) (because I couldn't find a fix)
I created a client side GWT RPC call queue.
Any RPC call made by the UI was registring the call to the queue, and the queue would manage (during high load, read delay), the actual execution of the calls.
It acted similar to a thread pool. I had a constant of how many parallel calls I can have at one time, and also a minimum time interval between two calls. I believe it was eventually set to 200 milliseconds.
So by doing the above I (almost) never got that issue. The frequency was so low, nobody noticed it anymore.
My guess of the cause below:
I believe the GWT framework has some maps that use a key that depends on the timestamp of the calls, and if two calls happen at the same time, the map could switch the calls, messing up the results to calls mapping.