persistence: порядковая нумерация async SaveMessage (старое состояние не перезапишет новое) + очистка при удалении
This commit is contained in:
@@ -46,6 +46,11 @@ var (
|
|||||||
seqMu sync.Mutex
|
seqMu sync.Mutex
|
||||||
queueWriteSeq = map[string]uint64{}
|
queueWriteSeq = map[string]uint64{}
|
||||||
tenantWriteSeq = map[string]uint64{}
|
tenantWriteSeq = map[string]uint64{}
|
||||||
|
// msgWriteSeq — порядковая нумерация async-записей ОТДЕЛЬНЫХ сообщений
|
||||||
|
// (ключ "{queueKey}|{uuid}"). Без неё два SaveMessage одного сообщения из
|
||||||
|
// разных горутин могли завершиться вразнобой: старое состояние перезаписало
|
||||||
|
// бы новое. Записи удаляются при удалении сообщения (DeleteMessagePersist и др.).
|
||||||
|
msgWriteSeq = map[string]uint64{}
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -260,7 +265,12 @@ func SaveMessage(queueKey string, msg *models.SqsMessage) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
hashKey := redisMsgHashPrefix + queueKey
|
hashKey := redisMsgHashPrefix + queueKey
|
||||||
|
msgKey := queueKey + "|" + msg.Uuid
|
||||||
|
writeSeq := nextMsgWriteSeq(msgKey)
|
||||||
asyncWrite(func() {
|
asyncWrite(func() {
|
||||||
|
if !isLatestMsgWriteSeq(msgKey, writeSeq) {
|
||||||
|
return
|
||||||
|
}
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
if err := Client.Load().HSet(ctx, hashKey, msg.Uuid, string(data)).Err(); err != nil {
|
if err := Client.Load().HSet(ctx, hashKey, msg.Uuid, string(data)).Err(); err != nil {
|
||||||
@@ -371,6 +381,7 @@ func DeleteMessagePersist(queueKey string, msgUuid string) error {
|
|||||||
if err := Client.Load().HDel(ctx, hashKey, msgUuid).Err(); err != nil {
|
if err := Client.Load().HDel(ctx, hashKey, msgUuid).Err(); err != nil {
|
||||||
return fmt.Errorf("HDel message %s/%s: %w", queueKey, msgUuid, err)
|
return fmt.Errorf("HDel message %s/%s: %w", queueKey, msgUuid, err)
|
||||||
}
|
}
|
||||||
|
clearMsgWriteSeq(queueKey, msgUuid)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -386,6 +397,7 @@ func DeleteMessagesPersist(queueKey string, uuids []string) error {
|
|||||||
if err := Client.Load().HDel(ctx, hashKey, uuids...).Err(); err != nil {
|
if err := Client.Load().HDel(ctx, hashKey, uuids...).Err(); err != nil {
|
||||||
return fmt.Errorf("HDel messages %s (%d): %w", queueKey, len(uuids), err)
|
return fmt.Errorf("HDel messages %s (%d): %w", queueKey, len(uuids), err)
|
||||||
}
|
}
|
||||||
|
clearMsgWriteSeq(queueKey, uuids...)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -402,6 +414,7 @@ func PurgeMessagesPersist(queueKey string) {
|
|||||||
if err := Client.Load().Del(ctx, hashKey).Err(); err != nil {
|
if err := Client.Load().Del(ctx, hashKey).Err(); err != nil {
|
||||||
log.Errorf("persistence: DEL messages hash %s: %v", queueKey, err)
|
log.Errorf("persistence: DEL messages hash %s: %v", queueKey, err)
|
||||||
}
|
}
|
||||||
|
clearAllMsgWriteSeq(queueKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteQueue — удаляет метаданные очереди И все её сообщения из Redis асинхронно.
|
// DeleteQueue — удаляет метаданные очереди И все её сообщения из Redis асинхронно.
|
||||||
@@ -653,6 +666,41 @@ func isLatestQueueWriteSeq(key string, seq uint64) bool {
|
|||||||
return queueWriteSeq[key] == seq
|
return queueWriteSeq[key] == seq
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func nextMsgWriteSeq(key string) uint64 {
|
||||||
|
seqMu.Lock()
|
||||||
|
defer seqMu.Unlock()
|
||||||
|
msgWriteSeq[key]++
|
||||||
|
return msgWriteSeq[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
func isLatestMsgWriteSeq(key string, seq uint64) bool {
|
||||||
|
seqMu.Lock()
|
||||||
|
defer seqMu.Unlock()
|
||||||
|
return msgWriteSeq[key] == seq
|
||||||
|
}
|
||||||
|
|
||||||
|
// clearMsgWriteSeq — удаляет записи нумерации для удалённых сообщений
|
||||||
|
// (иначе msgWriteSeq рос бы бесконечно).
|
||||||
|
func clearMsgWriteSeq(queueKey string, uuids ...string) {
|
||||||
|
seqMu.Lock()
|
||||||
|
defer seqMu.Unlock()
|
||||||
|
for _, u := range uuids {
|
||||||
|
delete(msgWriteSeq, queueKey+"|"+u)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// clearAllMsgWriteSeq — удаляет ВСЕ записи нумерации для очереди (purge).
|
||||||
|
func clearAllMsgWriteSeq(queueKey string) {
|
||||||
|
prefix := queueKey + "|"
|
||||||
|
seqMu.Lock()
|
||||||
|
defer seqMu.Unlock()
|
||||||
|
for k := range msgWriteSeq {
|
||||||
|
if strings.HasPrefix(k, prefix) {
|
||||||
|
delete(msgWriteSeq, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func nextTenantWriteSeq(id string) uint64 {
|
func nextTenantWriteSeq(id string) uint64 {
|
||||||
seqMu.Lock()
|
seqMu.Lock()
|
||||||
defer seqMu.Unlock()
|
defer seqMu.Unlock()
|
||||||
|
|||||||
Reference in New Issue
Block a user