Товарищи поделитесь опытом.
На последнем проекте стал замечать очень странное поведение.
Начну с вводных данных:
есть такая общая задача - получить из базы "свободные" данные, тут же пометить как "занято для работы", отдать пользователю. Пользователь работает с данными, сохраняет и "освобождает" их. Естественно между получить данные, отметить как занято для работы должен работать 1 поток.
Но заметил, что ОЧЕНЬ часто нашим пользователям выдаются одни и те же данные. КАК? Оказывается что они как-то умудряются одновременно послать запрос и одновременно получить одни и те же данные из базы, отметить их как "занятые". Это конечно возможно с точки зрения теории вероятности послать одновременный запрос и попасть в один и тот же промежуток с миллисекунды. Но млин, не каждый же день!!!
Погуглил на эту тему и нашел модификатор SOQL запроса FOR UPDATE. Но это немного не то
Данные то все равно могут получить "одновременно" но изменить сможет кто-то один (тот кто первый получил). Другой получит Exception.
А как можно в Salesforce организовать очередь? В других языках программирования это очень популярная тема "Concurrency", есть ли что-то похожее в Salesforce? Вот надо мне чтобы в метод выполнялся гарантированно только в одном потоке, а остальные ждали своей очереди.
Может есть какие костыли на эту тему?
Есть очереди для Jobs - https://www.salesforce.com/us/developer/docs/apexcode/Content/apex_queueing_jobs.htm
Это не то. Это не из области запрос-ответ. Нужно чтобы между запрос-ответ код выполнялся по очереди.
Но у меня такое предчувствие, что в Salesforce этого нет. Странно что никто до этого не сталкивался с такими проблемами.
Вот думаю, а тема то очень интересная.
Вот придумал пример из жизни.
У меня есть объект в базе для которого я в триггере по сложному алгоритму проверяю на дубли в before_insert.
Получается что может возникнуть ситуация конкурентного выполнения 2х DML оепраций в одно и тоже время. Триггер проверил на дубли (дублей нет), но до момента записи в базу другой поток успевает создать запись-дубль. Но так как проверка уже прошла, то первая DML операция отрабатывает успешно. Получается что вроде проверка есть, но и дубли в базе тоже есть?
Или все-таки 2 DML операции не могут выполниться одновременно?
Не могут запись будет заблокирована.
Есть даже алгоритм для воспроизведенеия ошибки LOCKED.
Ну это уже хорошо. Осталось разобраться с конкурентным выполнением самого кода.
Абсолютно согласен, не могут. Происходит примерно так: первое вызов триггера делает SELECT ... FOR UPDATE, второй вызов триггера будет ждать в том же месте на том же SELECT ... FOR UPDATE и так будет продолжаться пока первый вызов триггера не закоммитит транзакцию (важен имменно конец транзакции, DML в коде триггера не разблокирует записи). Ну или будет Exception, потому что первый вызов триггера долго не может закоммитить.
Внимание, лочить везде надо в одинаковой последовательности, иначе может быть deadlock.
Конкурентное выполнение кода, тут наверное неважно, потому как общего у друх транзакций только данные из базы. Да и в Apex все равно нет примитивов синхронизации.
Как часто вы используете FOR UPDATE вручную в коде?