-
Notifications
You must be signed in to change notification settings - Fork 252
Instantiate RetryHeap and RetryHeapProcessor if concurrency enabled #1974
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
35d5482
9cf39fa
1e36982
e156917
d53905a
7834bad
fe52e65
78cc945
e136db7
0aa65b6
eebd44e
c3b0195
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,11 +5,12 @@ package pusher | |
|
|
||
| import ( | ||
| "container/heap" | ||
| "errors" | ||
| "sync" | ||
| "time" | ||
|
|
||
| "github.com/influxdata/telegraf" | ||
|
|
||
| "github.com/aws/amazon-cloudwatch-agent/internal/retryer" | ||
| ) | ||
|
|
||
| // retryHeapImpl implements heap.Interface for logEventBatch sorted by nextRetryTime | ||
|
|
@@ -40,7 +41,7 @@ func (h *retryHeapImpl) Pop() interface{} { | |
|
|
||
| // RetryHeap manages failed batches during their retry wait periods | ||
| type RetryHeap interface { | ||
| Push(batch *logEventBatch) error | ||
| Push(batch *logEventBatch) | ||
| PopReady() []*logEventBatch | ||
| Size() int | ||
| Stop() | ||
|
|
@@ -52,34 +53,38 @@ type retryHeap struct { | |
| semaphore chan struct{} // Size enforcer | ||
| stopCh chan struct{} | ||
| maxSize int | ||
| stopped bool | ||
| logger telegraf.Logger | ||
| } | ||
|
|
||
| var _ RetryHeap = (*retryHeap)(nil) | ||
|
|
||
| // NewRetryHeap creates a new retry heap with the specified maximum size | ||
| func NewRetryHeap(maxSize int) RetryHeap { | ||
| func NewRetryHeap(maxSize int, logger telegraf.Logger) RetryHeap { | ||
| rh := &retryHeap{ | ||
| heap: make(retryHeapImpl, 0, maxSize), | ||
| maxSize: maxSize, | ||
| semaphore: make(chan struct{}, maxSize), // Semaphore for size enforcement | ||
| stopCh: make(chan struct{}), | ||
| logger: logger, | ||
| } | ||
| heap.Init(&rh.heap) | ||
| return rh | ||
| } | ||
|
|
||
| // Push adds a batch to the heap, blocking if full | ||
| func (rh *retryHeap) Push(batch *logEventBatch) error { | ||
| func (rh *retryHeap) Push(batch *logEventBatch) { | ||
| // Acquire semaphore slot (blocks if at maxSize capacity) | ||
| select { | ||
| case rh.semaphore <- struct{}{}: | ||
| // add batch to heap with mutex protection | ||
| rh.mutex.Lock() | ||
| heap.Push(&rh.heap, batch) | ||
| rh.mutex.Unlock() | ||
| return nil | ||
| case <-rh.stopCh: | ||
| return errors.New("retry heap stopped") | ||
| // RetryHeap is stopped, drop the batch | ||
| rh.logger.Errorf("Stop requested for %v/%v failed for PutLogEvents, request dropped.", batch.Group, batch.Stream) | ||
| batch.updateState() | ||
|
agarakan marked this conversation as resolved.
|
||
| } | ||
| } | ||
|
|
||
|
|
@@ -111,24 +116,36 @@ func (rh *retryHeap) Size() int { | |
|
|
||
| // Stop stops the retry heap | ||
| func (rh *retryHeap) Stop() { | ||
| if rh.stopped { | ||
| return | ||
| } | ||
| close(rh.stopCh) | ||
| rh.stopped = true | ||
| } | ||
|
|
||
| // RetryHeapProcessor manages the retry heap and moves ready batches back to sender queue | ||
| type RetryHeapProcessor struct { | ||
| retryHeap RetryHeap | ||
| senderPool Sender | ||
| retryer *retryer.LogThrottleRetryer | ||
| stopCh chan struct{} | ||
| logger telegraf.Logger | ||
| stopped bool | ||
| maxRetryDuration time.Duration | ||
| wg sync.WaitGroup | ||
| } | ||
|
|
||
| // NewRetryHeapProcessor creates a new retry heap processor | ||
| func NewRetryHeapProcessor(retryHeap RetryHeap, senderPool Sender, logger telegraf.Logger, maxRetryDuration time.Duration) *RetryHeapProcessor { | ||
| func NewRetryHeapProcessor(retryHeap RetryHeap, workerPool WorkerPool, service cloudWatchLogsService, targetManager TargetManager, logger telegraf.Logger, maxRetryDuration time.Duration, retryer *retryer.LogThrottleRetryer) *RetryHeapProcessor { | ||
| // Create processor's own sender and senderPool | ||
| // Pass retryHeap so failed batches go back to RetryHeap instead of blocking on sync retry | ||
| sender := newSender(logger, service, targetManager, maxRetryDuration, retryHeap) | ||
| senderPool := newSenderPool(workerPool, sender) | ||
|
Comment on lines
+140
to
+143
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: Could this be done outside of the RetryHeapProcessor constructor? Could just pass in a sender and have
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will come back to this in a separate PR since it doesnt affect functionality but does require refactoring the retryHeapProcessor constructor. Currently it seems like per-component dependencies are all created within the component that uses them. |
||
|
|
||
| return &RetryHeapProcessor{ | ||
| retryHeap: retryHeap, | ||
| senderPool: senderPool, | ||
| retryer: retryer, | ||
| stopCh: make(chan struct{}), | ||
| logger: logger, | ||
| stopped: false, | ||
|
|
@@ -138,6 +155,7 @@ func NewRetryHeapProcessor(retryHeap RetryHeap, senderPool Sender, logger telegr | |
|
|
||
| // Start begins processing the retry heap every 100ms | ||
| func (p *RetryHeapProcessor) Start() { | ||
| p.wg.Add(1) | ||
| go p.processLoop() | ||
| } | ||
|
|
||
|
|
@@ -150,12 +168,16 @@ func (p *RetryHeapProcessor) Stop() { | |
| // Process any remaining batches before stopping | ||
| p.processReadyMessages() | ||
|
|
||
| p.retryer.Stop() | ||
| p.senderPool.Stop() | ||
| close(p.stopCh) | ||
| p.wg.Wait() | ||
| p.stopped = true | ||
|
agarakan marked this conversation as resolved.
|
||
| } | ||
|
|
||
| // processLoop runs the main processing loop | ||
| func (p *RetryHeapProcessor) processLoop() { | ||
| defer p.wg.Done() | ||
| ticker := time.NewTicker(100 * time.Millisecond) | ||
| defer ticker.Stop() | ||
|
|
||
|
|
@@ -171,6 +193,10 @@ func (p *RetryHeapProcessor) processLoop() { | |
|
|
||
| // processReadyMessages checks the heap for ready batches and moves them back to sender queue | ||
| func (p *RetryHeapProcessor) processReadyMessages() { | ||
| if p.stopped { | ||
| return | ||
| } | ||
|
|
||
| readyBatches := p.retryHeap.PopReady() | ||
|
|
||
| for _, batch := range readyBatches { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.