go.ligato.io/vpp-agent/v3@v3.5.0/plugins/kvscheduler/txn_queue.go (about)

     1  // Copyright (c) 2018 Cisco and/or its affiliates.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at:
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package kvscheduler
    16  
    17  import (
    18  	"context"
    19  	"time"
    20  
    21  	"go.ligato.io/cn-infra/v2/logging"
    22  
    23  	kvs "go.ligato.io/vpp-agent/v3/plugins/kvscheduler/api"
    24  )
    25  
    26  // enqueueTxn adds transaction into the FIFO queue (channel) for execution.
    27  func (s *Scheduler) enqueueTxn(txn *transaction) error {
    28  	if txn.ctx == nil {
    29  		txn.ctx = context.TODO()
    30  	}
    31  	//trace.Log(txn.ctx, "txn", "enqueue")
    32  	if txn.txnType == kvs.NBTransaction && txn.nb.isBlocking {
    33  		select {
    34  		case <-s.ctx.Done():
    35  			return kvs.ErrClosedScheduler
    36  		case s.txnQueue <- txn:
    37  			reportQueued(1)
    38  			return nil
    39  		}
    40  	}
    41  	select {
    42  	case <-s.ctx.Done():
    43  		return kvs.ErrClosedScheduler
    44  	case s.txnQueue <- txn:
    45  		reportQueued(1)
    46  		return nil
    47  	default:
    48  		reportTxnDropped()
    49  		return kvs.ErrTxnQueueFull
    50  	}
    51  }
    52  
    53  // dequeueTxn pulls the oldest queued transaction.
    54  func (s *Scheduler) dequeueTxn() (txn *transaction, canceled bool) {
    55  	select {
    56  	case <-s.ctx.Done():
    57  		return nil, true
    58  	case txn = <-s.txnQueue:
    59  		reportQueued(-1)
    60  		//trace.Log(txn.ctx, "txn", "dequeue")
    61  		return txn, false
    62  	}
    63  }
    64  
    65  // enqueueRetry schedules retry for failed operations.
    66  func (s *Scheduler) enqueueRetry(args *retryTxn) {
    67  	go s.delayRetry(args)
    68  }
    69  
    70  // delayRetry postpones retry until a given time period has elapsed.
    71  func (s *Scheduler) delayRetry(args *retryTxn) {
    72  	s.wg.Add(1)
    73  	defer s.wg.Done()
    74  
    75  	select {
    76  	case <-s.ctx.Done():
    77  		return
    78  	case <-time.After(args.delay):
    79  		err := s.enqueueTxn(&transaction{
    80  			txnType: kvs.RetryFailedOps,
    81  			retry:   args,
    82  			created: time.Now(),
    83  		})
    84  		if err != nil {
    85  			s.Log.WithFields(logging.Fields{
    86  				"txnSeqNum": args.txnSeqNum,
    87  				"err":       err,
    88  			}).Warn("Failed to enqueue retry transaction for failed operations")
    89  			s.enqueueRetry(args) // try again with the same time period
    90  		}
    91  	}
    92  }