Що робити зі станом?

Спробую написати коротше та зрозуміліше.(Можливо загубив деталі)

Стан: : Краще почати з історії

Не так давно, я почав розробку власного телеграм боту. Бот має chain-message структуру, тобто коли користувач натискає кнопку/викликає команду/пише звичайне повідомлення спрацьовує задана функція з заданими параметрами з кнопки(вони знаходяться в полі callback_id), а для того щоб передавати якісь параметри… ну…. я їх просто передавав за допомогою нижьної лінії. Вони мали ось такий вигляд:

superUsefulMethod_6317185824_saIgk3wO_10_require

де метод superUseful приймає user_id, file_id якогось малюнку, айді пакунка, і вже якась побічна дія.

Тобто ідея була кожного разу акумулювати параметри за допомогою купи функцій та в кінці їх виконувати в кінечній функції.

Так, саме так я й передавав всі данні в колбеки з кнопок, зберігав їх в базі данних прив’язаних до користувача. Для спрощення цієї процедури я ще створював допоміжні методи….

@required()
@action("cb")
async admSendMessage()

@required()
@action("msg")
async admSendMessage2(...args: string[])

@required()
@action("msg")
async admSendMessage3(...args: string[])

До речі так, у зв’язку з використанням TypeScript це ще я прикрасив декораторами. Але повертаючись до теми, структура проєкту мала дууууже жахливий вигляд, й читаємість коду була екстримально малою.

Після довгих роздумів я ризикнув ( ну точніше як ризикнув, нічого втрачати, аудиторія бота 30 людей ) й створив окрему табличку в БД:

(Я прибрав зайвий контент з панелькі)

model Action {
id           String    @unique
name         String
params       String? // An array actually
beenExecuted Boolean   @default(false)
methods      String?
}

І почав її додавати до всіх місць де треба було більше ніж одна дія. І буквально відразу же я зрозумів наскільки це є ефективніше й більш лаконічно.

Стан: : Структура

id - записується в стан користувача з префіксом, щоб можна було зрозуміти.

name/methods - це дозволені функції

params - масив з переданих данних, саме цей елемент відіграє значущу роль у вирішенні комплексних проблем.

Стан: : Як працює

Якщо користувач отримав цей стан і якщо користувач дійшов до функції яка є в name/methods, то вони виконуються з заданими параметрами. Це було чудове рішення, отже тепер я можу створити одну функцію й акумулювати параметри в одній функції.

Код отримав такий вигляд:

@required()
async admSendMessage(userId?: number, text?: String)

Тут всі параметри є опціональні. Насправді кожну наступну дію вони один за одним заповнюються. В самій функції відбувається перевірка на їх наявність.

Стан: : Плюси та Мінуси

Серед плюсів я би виділив:

І нажаль є мінуси:

Стан: : Ще варіант

На мою думку можна зберігати в /tmp файл з айді користувача та стана користувача. Через особливості TMPFS це робить все екстримально швидким. Мінус є один, і це те, якщо перезавантажити сервер, то стан зітреться.

Стан: : Кінцівка

Дякую що ви це прочитали. До речі, якщо вам цікаві схожі рішення, можете глянути тут: 🧼 Soap Opera & Art House 🎨