enhancement
major
minor
defect
critical
major
minor
major
#30216
Background processing fails with the error "Session revision invalid" if the window saves data while it is running (jobs, AI runs)
A long-running background job in the React interface (<start-job>, com.top_logic.layout.view.job.JobRunner) terminates with the following exception if the user continues working in the same browser window and saves something while the job is running:
com.top_logic.knowledge.service.KnowledgeBaseRuntimeException: Session revision invalid: Expected 524 but got 522 in cache com.top_logic.knowledge.service.db2.ValueQueryCache@5d50f54d. The session revision may be the cached revision of the interaction, which means that a different interaction for the same session has updated the session concurrently. This leads to inconsistent data usage. Persistent data are not corrupted.
at com.top_logic.knowledge.service.db2.AbstractKBCache.getCurrentCache(AbstractKBCache.java:166)
at com.top_logic.knowledge.service.db2.AbstractKBCache.getValue(AbstractKBCache.java:106)
at com.top_logic.knowledge.service.db2.AbstractQueryCache.getValue(AbstractQueryCache.java:23)
at com.top_logic.element.model.PersistentModuleSingletons.getAllSingletons(PersistentModuleSingletons.java:308)
at com.top_logic.model.util.TLModelUtil.getAllGlobalClassesUncached(TLModelUtil.java:2475)
...
at com.top_logic.basic.thread.ThreadContextManager.inContext(ThreadContextManager.java:511)
...
Observed during an ETS project import (approximately 3 minutes in a transaction) that aborted at 95%. The same pattern affected other background tasks: Progress dialogs in the classic interface (ProgressDialog), chat and agent runs, parallel tool calls, sub-agents, agentChatAsync, test runs of data changes, saving view changes by agents, and prompt enhancement.
Cause
A sub-session must never execute two interactions simultaneously: The knowledge base sets the session revision for an interaction upon the first access; a commit from another interaction within the same sub-session changes the sub-session’s revision, while the first interaction remains at its old revision. The background processing described above ran using `ThreadContextManager.inContext(subSession, ...)` on a separate thread within the window’s or caller’s sub-session, i.e., concurrently with its requests. The inconsistency becomes apparent as soon as a KB cache is rebuilt (e.g., after the GC releases a SoftReference ): AbstractKBCache#getCurrentCache compares both revisions and throws the above exception.
Solution
- New entry point ThreadContextManager.inDerivedContext(SubSessionContext origin, job): executes the job in a new interaction on its own sub-session. It belongs to the same HTTP session as the original sub-session and carries its identity (person, context ID, locale, time zone, personal settings), but has its own session revision. It is not registered in the session and requires a thread without a running interaction.
- SubSessionContext#getOrigin() returns the sub-session from which a sub-session was derived (the first one in the case of multiple derivations). In addition, background operations continue to resolve through the origin for the window in which they are running: ReactWindowRegistry.registryDisplaying/windowDisplaying, ReactWindowReplay.inWindow, ChannelPublisher, the chat registries (ChatSessionRegistry, ChatViewBinding, ChatChannels), and RunPage.
- The JavaDoc for inContext specifies: only for work that is serialized against the sub-session’s other interactions (request thread, window lock).
- Migrated to inDerivedContext: JobRunner, ProgressDialog, ListComputation, AgentLoop (parallel tool calls), SubagentSpawner, AIScriptFunctions.agentChatAsync, ChangeDataTool (dry run), CommittedNow (view changes), ChatProcessor, PromptImprovementProcessor.
- Tests: TestDerivedContext (committing the original sub-session during an open interaction of the derived sub-session no longer fails during cache rebuilding; however, it does fail with inContext; identity and origin), TestJobRunnerSubSession, TestWindowOfSubSession, TestParallelCallContext, TestCommittedNow, TestPresentTool.
Note for Applications
Application code that runs on its own thread using `ThreadContextManager.inContext(<window sub-session>, ...)` while the window continues to be served should be migrated to `ThreadContextManager.inDerivedContext(...) `.