|
- /*
-
- Copyright (c) [2023] [pcm]
- [pcm-coordinator] is licensed under Mulan PSL v2.
- You can use this software according to the terms and conditions of the Mulan PSL v2.
- You may obtain a copy of Mulan PSL v2 at:
- http://license.coscl.org.cn/MulanPSL2
- THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
- EITHER EXPaRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
- MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
- See the Mulan PSL v2 for more details.
-
- */
-
- package mqs
-
- import (
- "fmt"
- "github.com/pkg/errors"
- "github.com/zeromicro/go-zero/core/queue"
- "github.com/zeromicro/go-zero/core/service"
- "github.com/zeromicro/go-zero/core/threading"
- "k8s.io/apimachinery/pkg/util/json"
- "sync"
- "time"
- )
-
- var InsQueue *workQueue
-
- type (
- ConsumeHandle func(v string) error
- ConsumeHandler interface {
- Consume(value string) error
- }
- workQueues struct {
- queues []queue.MessageQueue
- group *service.ServiceGroup
- }
- workQueue struct {
- topic string
- Beta *Beta
- handler ConsumeHandler
- consumerRoutines *threading.RoutineGroup
- }
- Beta struct {
- queue []t
-
- // dirty defines all of the items that need to be processed.
- dirty set
-
- // Things that are currently being processed are in the processing set.
- // These things may be simultaneously in the dirty set. When we finish
- // processing something and remove it from this set, we'll check if
- // it's in the dirty set, and if so, add it to the queue.
- processing set
-
- cond *sync.Cond
- }
- empty struct{}
- t interface{}
- set map[t]empty
- )
-
- func (s set) has(item t) bool {
- _, exists := s[item]
- return exists
-
- }
-
- func (s set) insert(item t) {
- s[item] = empty{}
- }
-
- func (s set) delete(item t) {
- delete(s, item)
- }
-
- func (s set) len() int {
- return len(s)
- }
-
- func (b *Beta) Get() (item interface{}) {
- b.cond.L.Lock()
- defer b.cond.L.Unlock()
- for len(b.queue) == 0 {
- b.cond.Wait()
- }
- if len(b.queue) == 0 {
- // We must be shutting down.
- return nil
- }
-
- item = b.queue[0]
- // The underlying array still exists and reference this object, so the object will not be garbage collected.
- b.queue[0] = nil
- b.queue = b.queue[1:]
-
- b.processing.insert(item)
- b.dirty.delete(item)
-
- return item
- }
-
- func (b *Beta) Add(item interface{}) {
- b.cond.L.Lock()
- defer b.cond.L.Unlock()
-
- if b.dirty.has(item) {
- return
- }
-
- b.dirty.insert(item)
- if b.processing.has(item) {
- return
- }
-
- b.queue = append(b.queue, item)
- b.cond.Signal()
- }
- func (w *workQueue) Start() {
- w.startConsumers()
- w.consumerRoutines.Wait()
- }
-
- func (w *workQueue) Stop() {
- }
-
- func (w workQueues) Start() {
- for _, each := range w.queues {
- w.group.Add(each)
- }
- w.group.Start()
- }
-
- func (w workQueues) Stop() {
- w.group.Stop()
- }
-
- func (w *workQueue) startConsumers() {
- w.consumerRoutines.Run(func() {
- for {
- item := w.Beta.Get()
- println("开始消费 ")
- if item != nil {
- bytes, err := json.Marshal(item)
- if err != nil {
- return
- }
- w.consumeOne(string(bytes))
- println("开始消费3")
- }
- time.Sleep(1 * time.Second)
- }
- })
-
- }
-
- func (w *workQueue) consumeOne(value string) error {
- err := w.handler.Consume(value)
- return err
- }
-
- func newWorkQueue(topic string, handler ConsumeHandler) queue.MessageQueue {
- wq := &workQueue{
- topic: topic,
- Beta: &Beta{
- dirty: set{},
- processing: set{},
- cond: sync.NewCond(&sync.Mutex{}),
- },
- consumerRoutines: threading.NewRoutineGroup(),
- handler: handler}
- InsQueue = wq
- return wq
- }
-
- func MustNewQueue(topic string, handler ConsumeHandler) queue.MessageQueue {
- q, err := NewQueue(topic, handler)
- if err != nil {
- fmt.Println("NewQueue报错")
- }
-
- return q
- }
-
- func NewQueue(topic string, handler ConsumeHandler) (queue.MessageQueue, error) {
- if len(topic) == 0 {
- return nil, errors.New("topic不能为空")
- }
-
- r := workQueues{
- group: service.NewServiceGroup(),
- }
- r.queues = append(r.queues, newWorkQueue(topic, handler))
-
- return r, nil
- }
|