mirror of
https://github.com/minio/minio.git
synced 2025-11-07 12:52:58 -05:00
Add an option to make bucket notifications synchronous (#17406)
With the current asynchronous behaviour in sending notification events to the targets, we can't provide guaranteed delivery as the systems might go for restarts. For such event-driven use-cases, we can provide an option to enable synchronous events where the APIs wait until the event is successfully sent or persisted. This commit adds 'MINIO_API_SYNC_EVENTS' env which when set to 'on' will enable sending/persisting events to targets synchronously.
This commit is contained in:
@@ -157,7 +157,7 @@ func (list *TargetList) TargetMap() map[TargetID]Target {
|
||||
}
|
||||
|
||||
// Send - sends events to targets identified by target IDs.
|
||||
func (list *TargetList) Send(event Event, targetIDset TargetIDSet, resCh chan<- TargetIDResult) {
|
||||
func (list *TargetList) Send(event Event, targetIDset TargetIDSet, resCh chan<- TargetIDResult, synchronous bool) {
|
||||
if atomic.LoadInt64(&list.currentSendCalls) > maxConcurrentTargetSendCalls {
|
||||
err := fmt.Errorf("concurrent target notifications exceeded %d", maxConcurrentTargetSendCalls)
|
||||
for id := range targetIDset {
|
||||
@@ -165,33 +165,40 @@ func (list *TargetList) Send(event Event, targetIDset TargetIDSet, resCh chan<-
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if synchronous {
|
||||
list.send(event, targetIDset, resCh)
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
var wg sync.WaitGroup
|
||||
for id := range targetIDset {
|
||||
list.RLock()
|
||||
target, ok := list.targets[id]
|
||||
list.RUnlock()
|
||||
if ok {
|
||||
wg.Add(1)
|
||||
go func(id TargetID, target Target) {
|
||||
atomic.AddInt64(&list.currentSendCalls, 1)
|
||||
defer atomic.AddInt64(&list.currentSendCalls, -1)
|
||||
defer wg.Done()
|
||||
tgtRes := TargetIDResult{ID: id}
|
||||
if err := target.Save(event); err != nil {
|
||||
tgtRes.Err = err
|
||||
}
|
||||
resCh <- tgtRes
|
||||
}(id, target)
|
||||
} else {
|
||||
resCh <- TargetIDResult{ID: id}
|
||||
}
|
||||
}
|
||||
wg.Wait()
|
||||
list.send(event, targetIDset, resCh)
|
||||
}()
|
||||
}
|
||||
|
||||
func (list *TargetList) send(event Event, targetIDset TargetIDSet, resCh chan<- TargetIDResult) {
|
||||
var wg sync.WaitGroup
|
||||
for id := range targetIDset {
|
||||
list.RLock()
|
||||
target, ok := list.targets[id]
|
||||
list.RUnlock()
|
||||
if ok {
|
||||
wg.Add(1)
|
||||
go func(id TargetID, target Target) {
|
||||
atomic.AddInt64(&list.currentSendCalls, 1)
|
||||
defer atomic.AddInt64(&list.currentSendCalls, -1)
|
||||
defer wg.Done()
|
||||
tgtRes := TargetIDResult{ID: id}
|
||||
if err := target.Save(event); err != nil {
|
||||
tgtRes.Err = err
|
||||
}
|
||||
resCh <- tgtRes
|
||||
}(id, target)
|
||||
} else {
|
||||
resCh <- TargetIDResult{ID: id}
|
||||
}
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
// Stats returns stats for targets.
|
||||
func (list *TargetList) Stats() TargetStats {
|
||||
t := TargetStats{}
|
||||
|
||||
@@ -249,7 +249,7 @@ func TestTargetListSend(t *testing.T) {
|
||||
for i, testCase := range testCases {
|
||||
testCase.targetList.Send(Event{}, map[TargetID]struct{}{
|
||||
testCase.targetID: {},
|
||||
}, resCh)
|
||||
}, resCh, false)
|
||||
res := <-resCh
|
||||
expectErr := (res.Err != nil)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user