flush builds the batch params, clears the in-memory batch, and writes to the database. On failure, the batch is queued for retry by the single retry worker goroutine. If the retry queue is full, the batch is dropped.
(ctx context.Context)
| 338 | // by the single retry worker goroutine. If the retry queue is full, |
| 339 | // the batch is dropped. |
| 340 | func (b *DBBatcher) flush(ctx context.Context) { |
| 341 | count := b.batchLen() |
| 342 | if count == 0 { |
| 343 | return |
| 344 | } |
| 345 | |
| 346 | params := b.buildParams() |
| 347 | |
| 348 | // Clear the batch before writing so the run loop can start |
| 349 | // accumulating new entries. |
| 350 | b.dedupedBatch = make(map[uuid.UUID]batchEntry, b.maxBatchSize) |
| 351 | b.nullConnIDBatch = nil |
| 352 | |
| 353 | // Use the batcher's context for normal operation so Close() |
| 354 | // can cancel hung writes. During shutdown (ctx already canceled), |
| 355 | // fall back to a bounded timeout. |
| 356 | writeCtx := b.ctx |
| 357 | if writeCtx.Err() != nil { |
| 358 | var cancel context.CancelFunc |
| 359 | writeCtx, cancel = context.WithTimeout(context.Background(), shutdownWriteTimeout) |
| 360 | defer cancel() |
| 361 | } |
| 362 | //nolint:gocritic // System-level batch operation for connection logs. |
| 363 | err := b.store.BatchUpsertConnectionLogs(dbauthz.AsConnectionLogger(writeCtx), params) |
| 364 | if err == nil { |
| 365 | return |
| 366 | } |
| 367 | |
| 368 | b.log.Error(ctx, "batch upsert failed, queueing for retry", |
| 369 | slog.Error(err), slog.F("count", count)) |
| 370 | |
| 371 | // Don't retry on shutdown. |
| 372 | if ctx.Err() != nil { |
| 373 | return |
| 374 | } |
| 375 | |
| 376 | select { |
| 377 | case b.retryCh <- params: |
| 378 | default: |
| 379 | b.log.Error(ctx, "retry queue full, dropping batch", |
| 380 | slog.F("dropped", count)) |
| 381 | } |
| 382 | } |
| 383 | |
| 384 | func (b *DBBatcher) buildParams() database.BatchUpsertConnectionLogsParams { |
| 385 | count := b.batchLen() |
no test coverage detected