aadz
в общем, SQL-библиотека - это не ORM, а довольно низкоуровневое средство, на надо думать, что она все сделает за тебя и даже думать, что сделает правильно :(
aadz
А у тебя panic? Тогда я точно не понял вопроса. Сначал свой код покажи, как ты хотел это сделать?
Kanybek
func (s *server) CreatePayment(ctx context.Context, paymentReq *pb.PaymentRequest) (*pb.PaymentRequest, error) {
unique_key, storeError := model.StorePayment(db, paymentReq)
if storeError != nil {
return nil, storeError
}
return paymentReq, nil
}
func StorePayment(db *sqlx.DB, payment *pb.PaymentRequest) (uint64, error) {
tx := db.MustBegin()
var lastInsertId uint64
err := tx.QueryRow("INSERT INTO payments " +
"(total_order_price, discount, total_price_with_discount) " +
"VALUES($1, $2, $3) returning payment_id;",
payment.TotalOrderPrice,
payment.Discount,
payment.TotalPriceWithDiscount).Scan(&lastInsertId)
CheckErr(err)
commitError := tx.Commit()
CheckErr(commitError)
return lastInsertId, nil
}
сейчас все в одном потоке
серёжа
А лучше на pastebin хотя бы ;D
Daniel
содомия какая-то
Daniel
коллеги, вы бы спросили для начала, что такое "крашит на транзакциях"
Kanybek
http://pastebin.com/W6Maddm4
Daniel
так это
Daniel
что с транзакциями не так?
aadz
да, кажется тут с ТЦП/ИП и вобще этой проблематикой что-то не так. До баз данных дело еще даже не у всех доходит.
Kanybek
что с транзакциями не так?
Суть в том что таких мест много, тоесть одновременно StorePayment, StoreCustomer, StoreSupplier может вызвать, а db *sqlx.DB только одно, и все, лови panic, тоесть crash
aadz
func (s *server) CreatePayment(ctx context.Context, paymentReq *pb.PaymentRequest) (*pb.PaymentRequest, error) {
unique_key, storeError := model.StorePayment(db, paymentReq)
if storeError != nil {
return nil, storeError
}
return paymentReq, nil
}
func StorePayment(db *sqlx.DB, payment *pb.PaymentRequest) (uint64, error) {
tx := db.MustBegin()
var lastInsertId uint64
err := tx.QueryRow("INSERT INTO payments " +
"(total_order_price, discount, total_price_with_discount) " +
"VALUES($1, $2, $3) returning payment_id;",
payment.TotalOrderPrice,
payment.Discount,
payment.TotalPriceWithDiscount).Scan(&lastInsertId)
CheckErr(err)
commitError := tx.Commit()
CheckErr(commitError)
return lastInsertId, nil
}
сейчас все в одном потоке
Боюсь, ты спросил не тот вопрос. Согласись?
aadz
Mo, ты сообщение err от базы берешь при выполнении вызова библиотеки? Что в этом сообщении?
Daniel
Slava
а можно стектрейс?
aadz
только не в канал!
Daniel
aadz
ну... как-то... даже не знаю...
если тут так принято, то почему нет? :)
Daniel
не принято
Kanybek
сейчас восоздам данную проблему, stacktrace
aadz
для начала хоть воссоздай, что за паника такая :)
Kanybek
Че то не получается пока, работает, ни одной ошибки, продолжаю поиски...
Slava
в стек трейсе (или в ошибке) обычно есть ответ на все вопросы, лучше их не игнорировать
aadz
Слава, что можешь сказать про mutex? Они правда так глобально все замедляют?
aadz
Олдовые Сишники говорят, что mutex - это дико роняет производительность при каждом разе использования. А вот юзал и не чувствовал. Или и правда это так плохо?
Kanybek
panic: pq: sorry, too many clients already
goroutine 583 [running]:
panic(0x4188c0, 0xc420493680)
/usr/local/go/src/runtime/panic.go:500 +0x1a1
github.com/jmoiron/sqlx.(*DB).MustBegin(0xc4201ae0c0, 0x0)
/Users/ko/Desktop/gocode/src/github.com/jmoiron/sqlx/sqlx.go:316 +0x83
github.com/ko/sample/grpc/model.StorePayment(0xc4201ae0c0, 0xc4205a55a0, 0x0, 0x0, 0x0)
/Users/ko/Desktop/gocode/src/github.com/ko/sample/grpc/model/payment.go:37 +0x67
вот че кинуло
Kanybek
Вот на этом: tx := db.MustBegin()
aadz
Mo, вот о том я и говорил.
panic: pq: sorry, too many clients already
Делай все в одной транзакции тогда и коммить периодически, или по времени последнего коммита, или по количеству звыполненных запросов, по ситуации
aadz
Слава, код вот такой https://github.com/aadz/gopp
Куча мютексов, просто хотя бы чтобы акуратно считать статистичку. И, вроде, работает для моих нужд. Но отцы ругают
aadz
panic: pq: sorry, too many clients already
goroutine 583 [running]:
panic(0x4188c0, 0xc420493680)
/usr/local/go/src/runtime/panic.go:500 +0x1a1
github.com/jmoiron/sqlx.(*DB).MustBegin(0xc4201ae0c0, 0x0)
/Users/ko/Desktop/gocode/src/github.com/jmoiron/sqlx/sqlx.go:316 +0x83
github.com/ko/sample/grpc/model.StorePayment(0xc4201ae0c0, 0xc4205a55a0, 0x0, 0x0, 0x0)
/Users/ko/Desktop/gocode/src/github.com/ko/sample/grpc/model/payment.go:37 +0x67
вот че кинуло
К сожалению, библиотечка SQL думает что коннект к базе и транзакция - это одно и то же :( Подумай об том, хотя библиотечка и не права, конечно.
Kanybek
В соседней группе такое решение посоветовали, буду тестить
Kanybek
funct dbwriter(db DB) {
for data := range datachan {
db.Insert(data)
}
}
func main() {
go func() {
for {
datachan <- data
}
}()
go func() {
for {
datachan <- data
}
}()
go func() {
for {
datachan <- data
}
}()
}
aadz
Mo, я то же самое посоветовал, по сути. Ты просто не услышал.
aadz
но я бы не стал ТАК это делать.
Anonymous
Vladimir
https://www.reddit.com/r/golang/comments/5uj13w/chrome_extension_that_replaces_occurrences_of/
engelbart
Неплохое да
engelbart
Но зачем скрывать боль если ей можно упиваться
серёжа
aadz
I'm да не. Мне надо их лочить при записи, чтобы никто не читал. Читают дико редко, а пишут - часто. Но я тормозов что-то не заметил, если честно. А Сишники сказали - тормозной код с такими мютексами
aadz
Хотя, мютексы - это не про Go, это про UNIX в общем. Но, они работабают, что не может не радовать. :)
Daniel
Daniel
aadz
Это идея распараллелить коннекты. Но все равно, каждом коннекте все придется делать в рамках транзакции.
Daniel
а у нас есть средства регулировать размер пула коннектов в sql?
Daniel
впрочем - тут пул устроен иначе, чем в java
Daniel
там ты явно забираешь соединение, и явно отдаешь
aadz
Библиотека не права и не не неправа. Она просто предоставляет сервис слишком низкого уровня. А это не сразу все программисты на PHP могут понять.
Vladimir
Daniel
впрочем, тут ты тоже явно забираешь соединение, когда открываешь транзакцию
aadz
И, кажется,некоторые вещи в SQL-библиотечке называются слишком многообещающе, что как раз неправильно
Daniel
можно на атомиках и sleep устроить блокирование и лимитирование числа коннектов
aadz
мне вот так и не удалось что-то сдеать так, чтобы запросы по доступным коннектам распределялись, а если доступных нет - ждали. Кажется, SQL-библиотека этого как раз и не умеет.
aadz
Она умееет открыть столько коннектов, сколько сможет, а потом подохнуть :(
Daniel
ммм
Daniel
как-то так получилось, что меня это не коснулось
Daniel
видимо - я его никогда не использовал на бесконечном количестве рутин
Daniel
но тогда - атомик и слип
Daniel
или даже нет
Daniel
канал же!
engelbart
канал запросов льем туда и выгребаем так ведь?
engelbart
Например через n секунд или m запросов комитим
aadz
А никакого бесконечного количества рутин и не надо. Она сама наоткрывает тебе столько, сколько обработать потом сама же и не сможет. Просто это не pool, на самом деле, а просто список коннектов.
Daniel
aadz
И есть тупо метод не делать так много коннектов. Держать все в пределах транзакции. На транзакцию будет один коннект хотя бы :(
Daniel
если это не так - у нас все равно проблемы
Daniel
поэтому, собственно, и нет ничего такого в стандартном пуле - не требуется
Daniel
но именно в случае с транзакциями возможны блокировки и всплески
Daniel
поэтому, если уж возникла проблема, нао как-то буферизовать запросы
aadz
Если тебе надо программным (сложным) образом поменять значение какого-то поля в табличке со 15 миллионами записсей, и ты не делаешь это в транзакции - да, в Go это у тебя проблема... :(
aadz
Даниэль, не о буферизации речь. Буферизация там как раз есть. И открытие рутины не по делу с новым коннектом к базе. Речь о том, что работает это не так, как ожидалось
aadz
И это, кажется миллион раз уже обсуждалось везде... Дизайн не самый удачный у этой библиотеки, в общем
Daniel
ну - он просто низкоуровневый
Daniel
проблему не заметают под ковер
Daniel
но возникает проблема не в либе, а в дизайне снаружи
aadz
низкоуровневый дизайн? хм... хорошо сказано. :)
серёжа
/voteban