Race Condition in Translation Callback When Queue is Bypassed

Created on 28 May 2025, 15 days ago

Problem/Motivation

We’ve identified a potential race condition in the process() method of the translation callback route. This issue occurs when translation responses are handled immediately via callback, rather than using the queue-based processing, which was recently made optional as part of a new feature.

A recent change introduced support for dual translation processing modes:

Traditional queued mode (deferred and serialized).
* New immediate ("on-call") mode for real-time translation callbacks.
* While this brings performance and UX benefits, the on-call mode introduces concurrency risks not present with the queued approach.

When multiple translation responses target the same JobItem at the same time, each request loads the entity independently.
All processes then update their own copy of the translatable data and call save().
This results in a classic race condition, where the last save may overwrite previous updates, causing:
* Loss of some translation segments
* Incomplete or incorrect job item states
* Inaccurate status updates or premature transitions to review

Proposed resolution

Apply a lock using LockBackendInterface to prevent concurrent updates on the same job item.
Lock scope should be minimal (just the $jobItem read-modify-write block).
Optional: Log or queue rejected callbacks when the lock can't be acquired to avoid silent drops.

🐛 Bug report
Status

Active

Version

1.1

Component

Code

Created by

🇵🇱Poland alorenc Wolsztyn, 🇵🇱

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Production build 0.71.5 2024