feat(shared-sqs): Redis write-through persistence, RollingUpdate deploy (v0.1.11)
This commit is contained in:
@@ -1,13 +1,16 @@
|
||||
// Изменено: 2026-04-09
|
||||
// Изменено: 2026-04-10 — добавлена Redis-персистентность через пакет persistence
|
||||
// Tenant model и in-memory хранилище тенантов для shared-sqs.
|
||||
package tenant
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"shared-sqs/app/persistence"
|
||||
)
|
||||
|
||||
// Tenant — модель тенанта shared-sqs.
|
||||
@@ -68,6 +71,11 @@ func (s *TenantStore) Create(name string, maxQueues int) (*Tenant, error) {
|
||||
s.byAccessKey[t.AccessKey] = t
|
||||
s.mu.Unlock()
|
||||
|
||||
// Сохраняем в Redis асинхронно — сериализуем здесь, вне мьютекса
|
||||
if data, err := json.Marshal(t); err == nil {
|
||||
persistence.SaveTenantRaw(t.ID, data)
|
||||
}
|
||||
|
||||
return t, nil
|
||||
}
|
||||
|
||||
@@ -75,11 +83,12 @@ func (s *TenantStore) Create(name string, maxQueues int) (*Tenant, error) {
|
||||
// Используется только при инициализации демо-данных; не вызывается из user-facing API.
|
||||
func (s *TenantStore) CreateFixed(name string, maxQueues int, tenantID, accessKey, secretKey string) (*Tenant, error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
if _, exists := s.byID[tenantID]; exists {
|
||||
s.mu.Unlock()
|
||||
return nil, fmt.Errorf("tenant with id %s already exists", tenantID)
|
||||
}
|
||||
if _, exists := s.byAccessKey[accessKey]; exists {
|
||||
s.mu.Unlock()
|
||||
return nil, fmt.Errorf("tenant with access key %s already exists", accessKey)
|
||||
}
|
||||
t := &Tenant{
|
||||
@@ -93,6 +102,13 @@ func (s *TenantStore) CreateFixed(name string, maxQueues int, tenantID, accessKe
|
||||
}
|
||||
s.byID[t.ID] = t
|
||||
s.byAccessKey[t.AccessKey] = t
|
||||
s.mu.Unlock()
|
||||
|
||||
// Сохраняем в Redis асинхронно — seed-данные тоже персистируем
|
||||
if data, err := json.Marshal(t); err == nil {
|
||||
persistence.SaveTenantRaw(t.ID, data)
|
||||
}
|
||||
|
||||
return t, nil
|
||||
}
|
||||
|
||||
@@ -116,16 +132,30 @@ func (s *TenantStore) GetByID(id string) (*Tenant, bool) {
|
||||
// Ловушка #2: если удалить только из одного индекса — orphaned данные и memory leak.
|
||||
func (s *TenantStore) Delete(id string) bool {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
t, ok := s.byID[id]
|
||||
if !ok {
|
||||
s.mu.Unlock()
|
||||
return false
|
||||
}
|
||||
delete(s.byID, t.ID)
|
||||
delete(s.byAccessKey, t.AccessKey)
|
||||
s.mu.Unlock()
|
||||
|
||||
// Удаляем из Redis асинхронно
|
||||
persistence.DeleteTenant(id)
|
||||
return true
|
||||
}
|
||||
|
||||
// LoadTenant — добавляет тенанта в хранилище без сохранения в Redis.
|
||||
// Используется ТОЛЬКО при старте сервиса для восстановления состояния из Redis.
|
||||
// Не вызывать из user-facing кода — нет дедупликации ключей.
|
||||
func (s *TenantStore) LoadTenant(t *Tenant) {
|
||||
s.mu.Lock()
|
||||
s.byID[t.ID] = t
|
||||
s.byAccessKey[t.AccessKey] = t
|
||||
s.mu.Unlock()
|
||||
}
|
||||
|
||||
// List — список всех тенантов (для admin GET /tenants).
|
||||
func (s *TenantStore) List() []*Tenant {
|
||||
s.mu.RLock()
|
||||
|
||||
Reference in New Issue
Block a user