LINUX.ORG.RU

Конкурентное обновление таблицы с ресурсами

 , ,


0

2

Вкратце опишу задачу. У компании есть клиенты, от имени которых она ведет переписку с третьими сервисами используя google workspace.

У каждого email эккаунта в google workspace можно завести алиас с помощью api, и использовать его в дальнейшем для конкретной переписки. После окончания переписки алиас можно просто удалить с помощью того же api. Это нужно потому, что есть лимит на количество алиасов для каждого email эккаунта в google workspace.

Бэк реализован на python с использованием sqlalchemy. БД - postgres.

Поэтому возникла идея создать две таблицы. Одну - со списком имеющихся email эккаунтов. И вторую, где будет список использующихся в данный момент алиасов для каждого email.

То есть во второй таблице (aliases) будут следующие поля: id, email, alias_email.

Получается, когда мы начинаем новую переписку, мы должны создать новый алиас для любого email эккаунта, у которого не превышен лимит по алиасам.

То есть делаем запрос вроде

select email, count(*)
from aliases
group by email

А затем выбираем из результата любой email, у которого не превышен лимит и вставляем новую запись со свежим алиасом для этого email в эту же таблицу. Ну и создаем алиас помощью google workspace api.

При окончании переписки просто удаляем запись с алиасом из таблицы и удаляем с помощью api сам алиас.

Возникает ситуация гонок, надо бы на момент выбора алиаса лочить таблицу aliases.

Можно ли это сделать с помощью алхимии? И какие есть альтернативы в подобной ситуации, когда есть конкурентные запросы к таблице в целом, а не к конкретным записям?


Ответ на: комментарий от anonymous

В том то и дело, что мы можем запретить с помощью for update именно update конкретных записей, а не вставку новых на момент выбора алиаса.

Может можно было бы использовать этот механизм (select for update) при какой-то другой схеме данных для данной задачи, но пока не понимаю, как.

C
() автор топика
Ответ на: комментарий от masa

Покажу пример таблицы, чтобы было наглядней. Предположим, что лимит у нас 3 алиаса на email.

-----------------------------------------------------------
|. email                   |           alias_email        |
|---------------------------------------------------------|
| corporateemail1@gmail.com|          vasya@gmail.com     |
| corporateemail1@gmail.com|          lesha@gmail.com     |
| corporateemail1@gmail.com|          misha@gmail.com     |
| corporateemail2@gmail.com|          sanya@gmail.com     |
| corporateemail2@gmail.com|          vova@gmail.com      |
-----------------------------------------------------------

Отсюда мы сделаем запрос с group by, узнаем, что у corporateemail2@gmail.com есть еще не занятый алиас и вставим новую запись для этого email

| corporateemail2@gmail.com|          kostya@gmail.com     |

То есть по идее надо бы запретить вставку и удаление записей на момент выбора алиаса.

C
() автор топика
Ответ на: комментарий от gruy

SERIALIZABLE - неплохое решение, но как я понимаю, оно повлияет и на все остальные запросы к другим таблицам, то есть сильно уменьшит производительность системы в целом. Неужели создавать два коннекшна с разным уровнем изоляции - одно для для работы с обычными таблицами и другое для таблицы с алиасами?

C
() автор топика

id, email, alias_email

Ты сейчас просто послал нафиг третью нормальную форму.

emails: id, email aliases: id, email_id, alias

Не хочешь городить контекст менеджер который бы через текущий коннект дергал сырой SQL с блокировкой - используй распределенный мьютекс в коде.

anonymous
()
Ответ на: комментарий от anonymous

Ты сейчас просто послал нафиг третью нормальную форму.

emails: id, email aliases: id, email_id, alias

Да, я просто не стал до конца нормализовать таблицы. Скорей всего так и сделаю, как ты сказал - с email_id в таблице aliases.

Не хочешь городить контекст менеджер который бы через текущий коннект дергал сырой SQL с блокировкой - используй распределенный мьютекс в коде.

У меня есть мысль создать хранимую процедуру в postgres - там вроде можно сделать lock таблице aliases. Гляну насчет сырого sql, раз там можно тоже lock указать.

C
() автор топика