Size: a a a

2020 October 05

AK

Arseny Khoroshilov in Go-go!
Timofey
Реализация состояния в тележном боте. Есть диалог, в котором юзер последовательно заполняет данные, которые сохраняются в контексте
Типа
-Юзер ввёл данные1
-Сохранили в контексте и базе
-Попросили о следующих
-Юзер ввёл данные2
-Сохранили в контексте и базе
...
А зачем каждый раз писать в БД? Если юзеров не очень много, можно сделать же мапу, которая при graceful shutdown пишется в БД один раз. Ну или раз в time.Duration для безопасности, всё равно обращений к репозиторию тогда в коде намного меньше.
источник

RL

Ragnar Lodbrok in Go-go!
Timofey
Реализация состояния в тележном боте. Есть диалог, в котором юзер последовательно заполняет данные, которые сохраняются в контексте
Типа
-Юзер ввёл данные1
-Сохранили в контексте и базе
-Попросили о следующих
-Юзер ввёл данные2
-Сохранили в контексте и базе
...
А зачем на каждом этапе сохранять? Не проще ли в памяти держать юзера, запросить все данные и потом сохранить?
источник

T

Timofey in Go-go!
Необходимости каждый раз писать в базу нет, но хочется иметь интерфейс для хранища.
В данный момент в качестве хранилища как раз выступает обычная мапа, но по хорошему-то нужно мочь прозрачно её заменить на любую другую
источник

T

Timofey in Go-go!
Т.е. сейчас есть InMemoryStorage который реализует ObjectRepository, сохраняя всё просто в мапу
источник

ВС

Владимир Столяров... in Go-go!
https://github.com/qor/transition
Возможно подойдёт
источник

p

pragus in Go-go!
Timofey
Вечер в чатик) У вас есть какая-нибудь произвольная бизнес сущность. Ну допустим такая
type Object struct {
 ID string
 Property string
}

Типичный вариант использования - это обновить в ней поле, сохранить это изменения в базе данных и далее использовать изменённый объект.
Как лучше реализовать структуру Object + интерфейс репозитория? Какой из этих вариантов лучше?

Вариант 1

type Object struct {
 id string
 property string
 repository ObjectRepository
}

type ObjectRepository interface {
 Store(o Object) error
 GetByID(ID string) (Object, error)
 UpdateProperty(ID string, newProperty string) error
}

func NewObject(id string, property string, rep ObjectRepository) Object {//}
func (o *Object) ID() string { return o.id }
func (o *Object) Property() string { return o.property }
func (o *Object) SetProperty(value string) {
 o.property = value
 o.repository.UpdateProperty(o.ID, property)
}

Использование
o := NewObject("1", "Val1", r)
o.SetProperty("Val2")
//Use o

Вариант 2

type Object struct {
 Id string
 Property string
}

type ObjectRepository interface {
 Store(o Object) error
 GetByID(ID string) (Object, error)
 Update(Object) error //Copy all changes to db
}

Использование
o := Object{ID:"1", Property:"Val1"}
o.Property = "Val2"
r.Update(o)
//Use o
А потом нам надо обновить 1к объектов и начинаются страдания
источник

AK

Arseny Khoroshilov in Go-go!
Timofey
Т.е. сейчас есть InMemoryStorage который реализует ObjectRepository, сохраняя всё просто в мапу
Ну так сделайте этот интерфейс с методами get/update, а логику сохранения в базу спрячьте в имплементацию. Т.е. чтобы сам объект беспокоился о том, как и когда он пушит себя на диск.
источник

AK

Arseny Khoroshilov in Go-go!
Непонятно, зачем из хендлеров бота прямое взаимодействие с базой.
источник

p

pragus in Go-go!
Arseny Khoroshilov
Непонятно, зачем из хендлеров бота прямое взаимодействие с базой.
Может человек боится гонок ;)
источник

AK

Arseny Khoroshilov in Go-go!
pragus
Может человек боится гонок ;)
Так эта кеш-мапа же одна на все хендлеры.
источник

T

Timofey in Go-go!
Arseny Khoroshilov
Ну так сделайте этот интерфейс с методами get/update, а логику сохранения в базу спрячьте в имплементацию. Т.е. чтобы сам объект беспокоился о том, как и когда он пушит себя на диск.
Так так и сделано, хэндлер о базе ничего не знает, у него есть только интерфейс с методами get/update.

Задача стояла немного другая - как лучше реализовать случай, когда нам нужно часто обновлять объект и не иметь потом 2 объекта с различным состоянием, 1 в памяти изменённый а другой в базе не обновлённый
источник

T

Timofey in Go-go!
@anysound "чтобы сам объект беспокоился о том, как и когда он пушит себя на диск"
Вот тут поподробнее. Объект будет беспокоиться или хэндлер в котором объект используется?
источник

T

Timofey in Go-go!
Если объект, то это как раз вариант 1
источник

AK

Arseny Khoroshilov in Go-go!
Объект в данном контексте - это эта условная мапа.
источник

ЕО

Евгений Омельченко... in Go-go!
Timofey
Вечер в чатик) У вас есть какая-нибудь произвольная бизнес сущность. Ну допустим такая
type Object struct {
 ID string
 Property string
}

Типичный вариант использования - это обновить в ней поле, сохранить это изменения в базе данных и далее использовать изменённый объект.
Как лучше реализовать структуру Object + интерфейс репозитория? Какой из этих вариантов лучше?

Вариант 1

type Object struct {
 id string
 property string
 repository ObjectRepository
}

type ObjectRepository interface {
 Store(o Object) error
 GetByID(ID string) (Object, error)
 UpdateProperty(ID string, newProperty string) error
}

func NewObject(id string, property string, rep ObjectRepository) Object {//}
func (o *Object) ID() string { return o.id }
func (o *Object) Property() string { return o.property }
func (o *Object) SetProperty(value string) {
 o.property = value
 o.repository.UpdateProperty(o.ID, property)
}

Использование
o := NewObject("1", "Val1", r)
o.SetProperty("Val2")
//Use o

Вариант 2

type Object struct {
 Id string
 Property string
}

type ObjectRepository interface {
 Store(o Object) error
 GetByID(ID string) (Object, error)
 Update(Object) error //Copy all changes to db
}

Использование
o := Object{ID:"1", Property:"Val1"}
o.Property = "Val2"
r.Update(o)
//Use o
Вариант 1 не репозиторий, это что-то ужасное. Вариант 2 — классический репозиторий. Так обычно и делают. Можете, конечно, любой другой шаблон проектирования использовать, но любой из них требует явного сохранения
источник

AK

Arseny Khoroshilov in Go-go!
Вы в логике получаете данные только из мапы, поэтому тут гонок нет (+ по идее только один хендлер в любой момент должен менять состояние конкретного юзера, так что вообще гонок не должно быть).
А сама мапа (ну т.е. предварительно запущенная рутина) иногда пишет себя на диск. Хранение на диске же нужно чисто чтобы не сбрасываться при шатдауне, если я правильно понял. Так что если выдёргивать сервер из розетки не планируете - запись на диск можно производить только при graceful shutdown, а в рантайме работать только с in memory.
источник

НБ

Никита Бафометович... in Go-go!
Зачем воротить какие-то непонятные решения с мапами, если абсолютно безболезненно можно использовать тот же SQLite, если не охота возиться с сервером нормальной бдшки. Да хоть в файл пишите - Json
источник

PK

Phil Kulin in Go-go!
Евгений Омельченко
plan 9 изобретаете?
Плюмбинг
источник

T

Timofey in Go-go!
Да не, мапа нормальный и простой вариант. Но это не важно, так как это вопрос выбора конкретного инструмента хранения, он по хорошему должен быть более или менее изолирован от нашей логики. С json-ом или sqlite-ом вопрос будет тот же самый - норм ли сихронизировать изменение в объекте с базой принудительно.

Ну я так понял, что вариант 2 как раз классический и обычно следят за этой синхронизацией вручную)
источник

A

Alisher in Go-go!
formString := string(jsonString)
   fmt.Println(formString)
   conn, err := amqp.Dial("amqp://admin:admin@localhost:15672/")
   ch, _ := conn.Channel()
   ch.QueueDeclare(
     "first.queue",
     true,
     true,
     false,
     false,
     nil)

   failOnError(err, "Failed to connect to RabbitMq")

   defer conn.Close()




Error
: 2020/10/06 01:37:38 http: panic serving 127.0.0.1:64920: runtime error: invalid memory address or nil pointer dereference
goroutine 82 [running]:
источник