В прошлом вопросе думал насчёт реализации FSM и решил сделать с помощью redis.
Сделал простую реализацию FSM:
FSMfunc (f *FSM) GetState(ctx context.Context, userID int) (string, error) {
state, err := f.redisPool.Get(ctx, f.stateKey(userID)).Result()
if errors.Is(err, redis.Nil) {
return NilState, nil
} else if err != nil {
return "", err
}
return state, nil
}
func (f *FSM) SetState(ctx context.Context, userID int, state string) error {
return f.redisPool.Set(ctx, f.stateKey(userID), state, T).Err()
}
func (f *FSM) stateKey(userID int) string {
return fmt.Sprintf("user:%d:state", userID)
}
В коде бота меняю состояние примерно вот так:
Code// AddCategoryHandler ...
func (h *Handlers) AddCategoryHandler() tele.HandlerFunc {
return func(tb tele.Context) error {
ctx := context.Background()
if err := h.fsm.SetState(ctx, int(tb.Sender().ID), fsm.InputAddCategoryState); err != nil {
h.logger.Err(err).Msg("failed to set state")
return tb.Respond(&tele.CallbackResponse{
CallbackID: tb.Callback().ID,
Text: messages.InternalErrorStr,
ShowAlert: false,
URL: "",
})
} ....
Вроде бы все работает нормально, когда ботом пользуется мало человек, но когда идёт большой наплыв, примерно 100 RPS, то состояния могут ломаться, т.е если 1 человек нажал эту кнопку, и в это время другой тоже, то состояние может перейти другому пользователю. Итак вопрос: как этого избежать?