github.com/asynkron/protoactor-go@v0.0.0-20240308120642-ef91a6abee75/actor/priority_queue.go (about)

     1  package actor
     2  
     3  // A priority queue is a sort of meta-queue that uses a queue per priority level.
     4  // The underlying queues can be anything that implements the queue interface.
     5  //
     6  // Messages that implement the PriorityMessage interface (i.e. have a GetPriority
     7  // method) will be consumed in priority order first, queue order second. So if a
     8  // higher priority message arrives, it will jump to the front of the queue from
     9  // the consumer's perspective.
    10  //
    11  // There are 8 priority levels (0-7) because having too many levels impacts
    12  // performance. And 8 priority levels ought to be enough for anybody. ;)
    13  // This means your GetPriority method should return int8s between 0 and 7. If any
    14  // return values are higher or lower, they will be reset to 7 or 0, respectively.
    15  //
    16  // The default priority level is 4 for messages that don't implement PriorityMessage.
    17  // If you want your message processed sooner than un-prioritized messages, have its
    18  // GetPriority method return a larger int8 value.
    19  // Likewise, if you'd like to de-prioritize your message, have its GetPriority method
    20  // return an int8 less than 4.
    21  
    22  const (
    23  	priorityLevels  = 8
    24  	DefaultPriority = int8(priorityLevels / 2)
    25  )
    26  
    27  type PriorityMessage interface {
    28  	GetPriority() int8
    29  }
    30  
    31  type priorityQueue struct {
    32  	priorityQueues []queue
    33  }
    34  
    35  func NewPriorityQueue(queueProducer func() queue) *priorityQueue {
    36  	q := &priorityQueue{
    37  		priorityQueues: make([]queue, priorityLevels),
    38  	}
    39  
    40  	for p := 0; p < priorityLevels; p++ {
    41  		q.priorityQueues[p] = queueProducer()
    42  	}
    43  
    44  	return q
    45  }
    46  
    47  func (q *priorityQueue) Push(item interface{}) {
    48  	itemPriority := DefaultPriority
    49  
    50  	if priorityItem, ok := item.(PriorityMessage); ok {
    51  		itemPriority = priorityItem.GetPriority()
    52  		if itemPriority < 0 {
    53  			itemPriority = 0
    54  		}
    55  		if itemPriority > priorityLevels-1 {
    56  			itemPriority = priorityLevels - 1
    57  		}
    58  	}
    59  
    60  	q.priorityQueues[itemPriority].Push(item)
    61  }
    62  
    63  func (q *priorityQueue) Pop() interface{} {
    64  	for p := priorityLevels - 1; p >= 0; p-- {
    65  		if item := q.priorityQueues[p].Pop(); item != nil {
    66  			return item
    67  		}
    68  	}
    69  	return nil
    70  }