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 }