Bug description
When validating (approving) a deposit, the system creates the document but
sometimes does not mark the deposit as validated. The moderator then retries,
which creates the document a second time (double validation).
Example: document https://folia.unifr.ch/manage/records/documents/detail/324501
was created, but the corresponding deposit stayed "to validate":
https://folia.unifr.ch/manage/deposit/324490/create
Root cause
The approve flow is neither atomic nor idempotent.
In DepositRecord.create_document()
(sonar/modules/deposits/api.py):
DocumentRecord.create(metadata, dbcommit=True, ...) commits the document
to the DB immediately (independently of the deposit).
- Files are added, then
document.reindex() runs — this dumps all resolved
fields and, if there are more than 1000 fields, ES throws here.
self["document"] = {"$ref": ...} (the deposit→document link) is only set
after the reindex.
In the review endpoint (sonar/modules/deposits/rest.py):
create_document() → deposit["status"] = VALIDATED → email → final
db.session.commit().
So if document.reindex() (or any later step) raises:
- the document is already committed (step 1),
- the deposit→document link (step 3) and
status = VALIDATED + final commit
never run → the deposit stays "to validate",
- the request returns 500.
Result: document created and committed, deposit not validated, no link
between them. On retry, create_document() runs again with no guard checking
self.get("document") → a second document is created.
The >1000-fields ES error is only the trigger that was observed; the
underlying defect is the non-atomic, non-idempotent design, which any
post-create_document() failure (email, network to ES, DB hiccup, a future
mapping change) can re-trigger.
Relation to #1014
#1014 (trim dumped linked fields) removes the specific >1000-fields trigger,
and the ES field limit was already raised in prod. Those reduce the
occurrences but do not fix the structural fragility addressed here.
Expected behavior
Validating a deposit either fully succeeds (document created and deposit
marked validated, atomically) or fully fails (nothing created, deposit
unchanged) — and can never create a duplicate document.
What should be done
- Atomicity (full rollback on failure): make document creation +
deposit status update a single transaction. If any step fails (including
indexing), roll everything back so neither a document nor a validated
deposit remains; the moderator can retry cleanly. Do not commit the
document independently before the deposit status is ready to commit.
- Idempotency guard: in
create_document(), if the deposit already has a
linked document (self.get("document")), do not create another one.
Acceptance criteria
Server: production (folia) — v1.8.2
Bug description
When validating (approving) a deposit, the system creates the document but
sometimes does not mark the deposit as validated. The moderator then retries,
which creates the document a second time (double validation).
Example: document https://folia.unifr.ch/manage/records/documents/detail/324501
was created, but the corresponding deposit stayed "to validate":
https://folia.unifr.ch/manage/deposit/324490/create
Root cause
The approve flow is neither atomic nor idempotent.
In
DepositRecord.create_document()(
sonar/modules/deposits/api.py):DocumentRecord.create(metadata, dbcommit=True, ...)commits the documentto the DB immediately (independently of the deposit).
document.reindex()runs — this dumps all resolvedfields and, if there are more than 1000 fields, ES throws here.
self["document"] = {"$ref": ...}(the deposit→document link) is only setafter the reindex.
In the
reviewendpoint (sonar/modules/deposits/rest.py):create_document()→deposit["status"] = VALIDATED→ email → finaldb.session.commit().So if
document.reindex()(or any later step) raises:status = VALIDATED+ final commitnever run → the deposit stays "to validate",
Result: document created and committed, deposit not validated, no link
between them. On retry,
create_document()runs again with no guard checkingself.get("document")→ a second document is created.The >1000-fields ES error is only the trigger that was observed; the
underlying defect is the non-atomic, non-idempotent design, which any
post-
create_document()failure (email, network to ES, DB hiccup, a futuremapping change) can re-trigger.
Relation to #1014
#1014 (trim dumped linked fields) removes the specific >1000-fields trigger,
and the ES field limit was already raised in prod. Those reduce the
occurrences but do not fix the structural fragility addressed here.
Expected behavior
Validating a deposit either fully succeeds (document created and deposit
marked validated, atomically) or fully fails (nothing created, deposit
unchanged) — and can never create a duplicate document.
What should be done
deposit status update a single transaction. If any step fails (including
indexing), roll everything back so neither a document nor a validated
deposit remains; the moderator can retry cleanly. Do not commit the
document independently before the deposit status is ready to commit.
create_document(), if the deposit already has alinked document (
self.get("document")), do not create another one.Acceptance criteria
validated, and thedeposit.documentlink set — all committed togetherpersisted and the deposit stays
to_validatenot create a second document
Server: production (folia) —
v1.8.2