WIP: Batch message INSERTs
This commit is contained in:
parent
499ac76c43
commit
b4933a5645
4 changed files with 107 additions and 8 deletions
56
util/batching_queue.go
Normal file
56
util/batching_queue.go
Normal file
|
@ -0,0 +1,56 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type BatchingQueue[T any] struct {
|
||||
batchSize int
|
||||
timeout time.Duration
|
||||
in []T
|
||||
out chan []T
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
func NewBatchingQueue[T any](batchSize int, timeout time.Duration) *BatchingQueue[T] {
|
||||
q := &BatchingQueue[T]{
|
||||
batchSize: batchSize,
|
||||
timeout: timeout,
|
||||
in: make([]T, 0),
|
||||
out: make(chan []T),
|
||||
}
|
||||
ticker := time.NewTicker(timeout)
|
||||
go func() {
|
||||
for range ticker.C {
|
||||
elements := q.popAll()
|
||||
if len(elements) > 0 {
|
||||
q.out <- elements
|
||||
}
|
||||
}
|
||||
}()
|
||||
return q
|
||||
}
|
||||
|
||||
func (c *BatchingQueue[T]) Push(element T) {
|
||||
c.mu.Lock()
|
||||
c.in = append(c.in, element)
|
||||
limitReached := len(c.in) == c.batchSize
|
||||
c.mu.Unlock()
|
||||
if limitReached {
|
||||
c.out <- c.popAll()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *BatchingQueue[T]) Pop() <-chan []T {
|
||||
return c.out
|
||||
}
|
||||
|
||||
func (c *BatchingQueue[T]) popAll() []T {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
elements := make([]T, len(c.in))
|
||||
copy(elements, c.in)
|
||||
c.in = c.in[:0]
|
||||
return elements
|
||||
}
|
25
util/batching_queue_test.go
Normal file
25
util/batching_queue_test.go
Normal file
|
@ -0,0 +1,25 @@
|
|||
package util_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"heckel.io/ntfy/util"
|
||||
"math/rand"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestConcurrentQueue_Next(t *testing.T) {
|
||||
q := util.NewBatchingQueue[int](25, 200*time.Millisecond)
|
||||
go func() {
|
||||
for batch := range q.Pop() {
|
||||
fmt.Printf("Batch of %d items\n", len(batch))
|
||||
}
|
||||
}()
|
||||
for i := 0; i < 1000; i++ {
|
||||
go func(i int) {
|
||||
time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
|
||||
q.Push(i)
|
||||
}(i)
|
||||
}
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue