P0.3: синхронный персист SendMessage до ответа 200
Добавлен persistence.SaveMessageSync (синхронный HSet, возвращает ошибку). SendMessage теперь пишет сообщение в Redis ДО возврата клиенту; при ошибке Redis сообщение откатывается из памяти и возвращается InternalError (новая ошибка в models/errors.go). Устраняет окно потери подтверждённого сообщения при краше пода между 200 OK и асинхронной записью.
This commit is contained in:
@@ -150,6 +150,29 @@ func SaveMessage(queueKey string, msg *models.SqsMessage) {
|
||||
})
|
||||
}
|
||||
|
||||
// SaveMessageSync — сохраняет ОДНО сообщение в Redis СИНХРОННО и возвращает ошибку.
|
||||
// Используется на пути SendMessage: ответ 200 клиенту должен выдаваться ТОЛЬКО
|
||||
// после фактической записи сообщения в Redis, иначе краш пода в окне между
|
||||
// ответом и async-записью приведёт к потере подтверждённого сообщения.
|
||||
// Ключ: ssq:msg:{queueKey}, поле: msg.Uuid, значение: JSON(SqsMessage).
|
||||
// Если Client == nil (memory-only режим) — возвращает nil (персистить некуда).
|
||||
func SaveMessageSync(queueKey string, msg *models.SqsMessage) error {
|
||||
if Client == nil {
|
||||
return nil
|
||||
}
|
||||
data, err := json.Marshal(msg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("marshal message %s/%s: %w", queueKey, msg.Uuid, err)
|
||||
}
|
||||
hashKey := redisMsgHashPrefix + queueKey
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||
defer cancel()
|
||||
if err := Client.HSet(ctx, hashKey, msg.Uuid, string(data)).Err(); err != nil {
|
||||
return fmt.Errorf("HSet message %s/%s: %w", queueKey, msg.Uuid, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SaveMessages — сохраняет несколько сообщений в Redis одним pipeline.
|
||||
// Вызывать под Lock.
|
||||
func SaveMessages(queueKey string, msgs []models.SqsMessage) {
|
||||
|
||||
Reference in New Issue
Block a user