Почему операции с мапой выполняются не в том порядке
Преамбула: Я в курсе, что порядок вывода элементов мапы не определен. Далее речь идет не о порядке выода элементов, а порядке выполнения функций.
Я написал методы для работы с мапой:
func (c *Cache) Save(key string, value any) {
c.Mutex.Lock()
defer c.Mutex.Unlock()
_, ok := c.Storage[key]
if ok {
c.Error = fmt.Errorf(errs.ErrKeyAlreadyExists, key)
return
}
c.Storage[key] = value
}
func (c *Cache) Get(key string) any {
c.Mutex.Lock()
defer c.Mutex.Unlock()
res, ok := c.Storage[key]
if !ok {
return struct{}{}
}
return res
}
func (c *Cache) Del(key string) {
c.Mutex.Lock()
defer c.Mutex.Unlock()
_, ok := c.Storage[key]
if !ok {
c.Error = fmt.Errorf(errs.ErrKeyIsUpset)
return
}
delete(c.Storage, key)
}
Вызываются они в некотором коде уровнем повыше.
func getStoredSession(refreshToken string) (models.Session, error) {
storedSession, ok := general.Get(cache.SessionsCache, refreshToken).(models.Session)
if !ok {
return models.Session{}, fmt.Errorf("%s", errs.ErrInvalidSession)
}
return storedSession, nil
}
func saveNewSession(newRefreshToken string, session models.Session) error {
general.Save(cache.SessionsCache, newRefreshToken, session)
log.Println("SAVING", cache.SessionsCache.Storage, cache.SessionsCache.Error)
return cache.SessionsCache.Error
}
func delSession(oldRefreshToken string) error {
general.Delete(cache.SessionsCache, oldRefreshToken)
log.Print("delete session...", oldRefreshToken)
return cache.SessionsCache.Error
}
Вызываются они через интерфейсные функции:
func Save(saver interfaces.SaveGeter, key string, value any) {
saver.Save(key, value)
}
func Get(geter interfaces.SaveGeter, key string) any {
return geter.Get(key)
}
func Delete(deleter interfaces.Deleter, key string) {
deleter.Del(key)
}
Когда я вызываю свои api через главную страницу сайта, Вызываю я их в определеном порядке.
Нужно сперва достать старую сессию, провести с ней работу и сгенерировать новую сессию(ключи естесственно разные), сохранить ее, удалить старую.
Вызваны в коде они ТОЧНО в указаном порядке
Но, при определенных обстоятельствах, порядок нарушается и я не могу понять почему.
Срабатвает так:
Сперва удаляет старую сессию, создает и сохраняет новую, пытается достать стару сессию(которая уже удалена)...Правильный порядок и неправильный порядок происходит в одном и том же куске кода....Я что не знаю о каких то свойствах мапы?
Я целый день пытаюсь понять почему delete срабатывает первым. Уже просто замучался.
UPD:
Добавляю код в котором нарушется порядок выполнения. Доп инфо в комментах
func RefreshToken(w http.ResponseWriter, r *http.Request) {
encoder := json.NewEncoder(w)
oldRefreshToken, err := getRefreshFromReq(r)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
encoder.Encode(&models.Repl{Error: err.Error()})
return
}
serviceDescription, err := getDecriptionFromReq(r)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
encoder.Encode(&models.Repl{Error: err.Error()})
return
}
// сперва нужно достать refresh сессию. Но этот фрагмент выполняется самым последним, что неожиданно.
storedSession, err := getStoredSession(oldRefreshToken)
if err != nil {
log.Println("ERRFETHINGSESSIONREFRESH", err, oldRefreshToken)
w.WriteHeader(http.StatusNotFound)
encoder.Encode(&models.Repl{Error: err.Error()})
return
}
service, err := getServiceByDescription(serviceDescription)
if err != nil {
w.WriteHeader(http.StatusNotFound)
encoder.Encode(&models.Repl{Error: err.Error()})
return
}
// Неожиданное поведение.
// delete выполняется раньше, чем getStoredSession, хотя getStoredSession выше по коду.
// Из-за этого вся функция работает некорректно.
// Первый refresh при логине пользователя срабатывает корректно и в правильном порядке
// Но если удалить на сайте куку содержащую access токен, то порядок ломается.
// Все параметры запросма для рефреша сессии приходят коректно.
// Проблема только в нарушении порядка в такой ситуации.
err = delSession(oldRefreshToken)
if err != nil {
log.Println(err)
w.WriteHeader(http.StatusInternalServerError)
encoder.Encode(&models.Repl{Error: err.Error()})
return
}
secret, err := getStoredSecret(storedSession.Uid)
if err != nil {
w.WriteHeader(http.StatusNotFound)
encoder.Encode(&models.Repl{Error: err.Error()})
return
}
refGen := refreshGen(service.Domain)
// проверяет не истекла ли сессия
// проверяет совпадает ли сервис из параметрах запроса с тем что лежит в refresh сессии.
validRefSession := general.ValidToken(&refGen, storedSession)
if !validRefSession {
w.WriteHeader(http.StatusUnauthorized)
encoder.Encode(&models.Repl{Error: errs.ErrInvalidSession})
return
}
general.GenToken(&refGen)
if refGen.Error != nil {
log.Println(refGen.Error)
return
}
newSession := genNewSession(storedSession.Uname, storedSession.Uid, service)
accGen := accessGen(service.Domain, newSession.Uname, secret)
general.GenToken(&accGen)
if accGen.Error != nil {
log.Println(accGen.Error)
return
}
tokens := prepareTokens(accGen.Token, refGen.Token, newSession.Uname)
err = saveNewSession(tokens.Refresh, newSession)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
encoder.Encode(&models.Repl{Error: err.Error()})
return
}
log.Println(cache.SessionsCache.Storage[tokens.Refresh], "<###")
encoder.Encode(tokens)
}
UPD2:
Нашел проблему. Она была в логике одной из мидлварей сайта. Был пропущен else либо return и сразу выполнялся ServeHTTP().
Но остался вопрос почему выполнялось все не в том порядке