P2.5: биллинг — воркер+буфер вместо горутины на операцию; корректный msg_count
RecordUsage теперь кладёт запись в буферизованный канал (1024), один воркер пишет в PG — убран навал горутин, ждущих коннект пула (было 5). При переполнении буфера запись дропается с логом (биллинг жертвуем ради стабильности). Для batch-операций (SendMessageBatch/DeleteMessageBatch/ChangeMessageVisibilityBatch) msg_count теперь реальное число записей, а не всегда 1.
This commit is contained in:
+40
-2
@@ -200,6 +200,36 @@ func metricsAuth(adminToken string, next http.Handler) http.Handler {
|
||||
})
|
||||
}
|
||||
|
||||
// countBatchEntries — подсчитывает число записей в batch-запросе SQS.
|
||||
// Для query-протокола записи идут как SendMessageBatchRequestEntry.N.Id (N=1..).
|
||||
// Для JSON-протокола считаем по количеству записей в массиве Entries (requestBody).
|
||||
// Возвращает 0 если определить не удалось (тогда биллинг запишет msg_count=1).
|
||||
func countBatchEntries(req *http.Request, action string) int {
|
||||
// Query-формат: считаем уникальные N в SendMessageBatchRequestEntry.N.Id и т.п.
|
||||
prefix := "SendMessageBatchRequestEntry."
|
||||
if action == "DeleteMessageBatch" {
|
||||
prefix = "DeleteMessageBatchRequestEntry."
|
||||
} else if action == "ChangeMessageVisibilityBatch" {
|
||||
prefix = "ChangeMessageVisibilityBatchRequestEntry."
|
||||
}
|
||||
if req.PostForm != nil || req.Form != nil {
|
||||
form := req.Form
|
||||
if form == nil {
|
||||
form = req.PostForm
|
||||
}
|
||||
count := 0
|
||||
for key := range form {
|
||||
if strings.HasPrefix(key, prefix) && strings.HasSuffix(key, ".Id") {
|
||||
count++
|
||||
}
|
||||
}
|
||||
if count > 0 {
|
||||
return count
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func actionHandler(w http.ResponseWriter, req *http.Request) {
|
||||
action := extractAction(req)
|
||||
start := time.Now()
|
||||
@@ -227,8 +257,16 @@ func actionHandler(w http.ResponseWriter, req *http.Request) {
|
||||
if queueName == "" {
|
||||
queueName = req.FormValue("QueueName")
|
||||
}
|
||||
// Billing: запись в PostgreSQL (async, no-op если billing выключен)
|
||||
billing.RecordUsage(t.ID, action, queueName, 1, msgBytes)
|
||||
// Billing: запись в PostgreSQL (async, no-op если billing выключен).
|
||||
// msgCount для batch-операций — число сообщений в батче; для прочих — 1.
|
||||
msgCount := 1
|
||||
if action == "SendMessageBatch" || action == "DeleteMessageBatch" ||
|
||||
action == "ChangeMessageVisibilityBatch" {
|
||||
if n := countBatchEntries(req, action); n > 0 {
|
||||
msgCount = n
|
||||
}
|
||||
}
|
||||
billing.RecordUsage(t.ID, action, queueName, msgCount, msgBytes)
|
||||
// Prometheus counters: requests + bytes
|
||||
metrics.RequestsTotal.WithLabelValues(t.ID, action).Inc()
|
||||
metrics.RequestBytesTotal.WithLabelValues(t.ID, action).Add(float64(msgBytes))
|
||||
|
||||
Reference in New Issue
Block a user