Sobes.tech
Senior

Ontwerpopdracht: er is een systeem voor snelreactiegroepen. Wanneer een signaal binnenkomt, reageren onmiddellijk drie groepen gelijktijdig. Alleen één groep moet worden gestuurd. Hoe doe je dat op transactieniveau in de database?

sobes.tech AI

Antwoord van 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()
}

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