Annotation Interface LongComputation
What it is for
Gemma sets hibernate.connection.handling_mode = DELAYED_ACQUISITION_AND_HOLD
(HibernateConfig), so a transaction holds its pooled connection from first statement to
commit — including through any stretch that issues no statements at all. The pool is configured
to recycle connections every 30 minutes (gemma.db.hikari.maxLifetime). A computation
that runs inside a transaction for longer than that is holding a connection the pool expects to
have turned over, and it is holding it for no reason: the computation does not use it.
Measured on production 2026-09-17: corrMat -force on GSE260875 spent 44 minutes in
quantile normalization inside one @Transactional(readOnly = true), then failed on its
next statement. Reads and writes on that path are cleanly separable from the arithmetic between
them, which is what makes holding the connection across it a defect rather than a cost.
The shape that is correct
Read in a short transaction, compute with none open, write in a short transaction. The
orchestrating class declares @Transactional(propagation = Propagation.NEVER) — the idiom
already used by PreprocessorServiceImpl,
DifferentialExpressionAnalyzerServiceImpl, OutlierFlaggingServiceImpl,
DataUpdaterImpl and a dozen others — and each step it calls carries its own annotation.
Because Spring AOP does not intercept private or self-invoked methods, the steps have to live on
a bean the orchestrator calls through its proxy; *HelperServiceImpl is the precedent.
Where to put it
On the method or constructor that is the computation, or on the class when every
entry point into it is one (LeastSquaresFit has eight constructors and all of them run
the fit). Do not put it on an orchestrator that merely reaches a computation — that is the thing
the rule is looking for, not a declaration.
TransactionSpanningComputeRuleTest fails the build when a @Transactional
method can reach one of these. Retention is RUNTIME because ArchUnit reads compiled
bytecode.
- See Also:
-
Optional Element Summary
Optional Elements
-
Element Details
-
value
String valueOptional note on what makes this one long — a measured duration, a complexity, the dataset that showed it. Read by whoever hits the rule and has to decide where the transaction boundary belongs.- Default:
""
-