Sobes.tech
Назад к вопросам
Senior
4

Задача на проектирование: есть система для групп быстрого реагирования. Пришёл сигнал, и сразу три группы на него откликнулись одновременно. Нужно послать только одну группу. Как это сделать на уровне транзакций в базе данных?

Компании, где спрашивали
purrweb

Ответ от нейросети

sobes.tech AI

Для решения задачи с одновременным откликом нескольких групп и выбором только одной на уровне транзакций в базе данных можно использовать механизм блокировок и уникальных ограничений.

Подход:

  1. Создайте таблицу, например, signal_assignments, где хранится информация о том, какая группа назначена на сигнал.
  2. При получении сигнала каждая группа пытается вставить запись с уникальным ключом по сигналу (например, signal_id с уникальным индексом).
  3. Первая транзакция, которая успешно вставит запись, «захватывает» сигнал.
  4. Остальные транзакции при попытке вставки получат ошибку уникального ограничения и должны откатиться или повторить попытку.

Пример на SQL:

CREATE TABLE signal_assignments (
    signal_id UUID PRIMARY KEY,
    group_id UUID NOT NULL
);

При обработке сигнала в транзакции:

BEGIN;
INSERT INTO signal_assignments(signal_id, group_id) VALUES (:signal_id, :group_id);
COMMIT;

Если вставка не удалась из-за уже существующей записи, значит сигнал уже назначен другой группе.

В Go с использованием транзакций:

func assignGroup(db *sql.DB, signalID, groupID string) error {
    tx, err := db.Begin()
    if err != nil {
        return err
    }
    defer tx.Rollback()

    _, err = tx.Exec(`INSERT INTO signal_assignments(signal_id, group_id) VALUES ($1, $2)`, signalID, groupID)
    if err != nil {
        // Ошибка уникального ограничения — сигнал уже назначен
        return err
    }

    return tx.Commit()
}

Таким образом, на уровне базы данных гарантируется, что только одна группа будет назначена на сигнал, несмотря на одновременные попытки.