1
1
package queue
2
2
3
3
import (
4
+ "errors"
4
5
"fmt"
5
6
"sync"
6
7
"time"
7
8
9
+ "github.com/leopoldxx/go-utils/concurrency"
8
10
"github.com/leopoldxx/go-utils/trace"
9
11
10
12
"context"
@@ -16,22 +18,35 @@ const (
16
18
)
17
19
18
20
// HandlerWrap function for Handler interface
19
- func HandlerWrap (f func (ctx context.Context , data []byte ) error ) * HandlerWrapper {
20
- return & HandlerWrapper {f }
21
+ func HandlerWrap (name string , f func (ctx context.Context , data []byte ) error ) * HandlerWrapper {
22
+ return & HandlerWrapper {name , f }
21
23
}
22
24
23
25
// HandlerWrapper for Handler
24
26
type HandlerWrapper struct {
25
- Impl func (ctx context.Context , data []byte ) error
27
+ NameValue string
28
+ Impl func (ctx context.Context , data []byte ) error
26
29
}
27
30
28
31
// Handle of hw
29
32
func (hw * HandlerWrapper ) Handle (ctx context.Context , data []byte ) error {
33
+ if hw == nil {
34
+ return errors .New ("nil handler" )
35
+ }
30
36
return hw .Impl (ctx , data )
31
37
}
32
38
39
+ // Name of the handler
40
+ func (hw * HandlerWrapper ) Name () string {
41
+ if hw == nil {
42
+ return "<nil>"
43
+ }
44
+ return hw .NameValue
45
+ }
46
+
33
47
// Handler of MsgQue
34
48
type Handler interface {
49
+ Name () string
35
50
Handle (ctx context.Context , data []byte ) error
36
51
}
37
52
@@ -76,40 +91,51 @@ func (mq *MsgQueue) Stop() {
76
91
77
92
// Run the background processor
78
93
func (mq * MsgQueue ) Run () {
94
+ handleBarrier := concurrency .NewBarrier (100 )
79
95
handle := func (mq * MsgQueue , mb * msgBody ) {
80
- var wg sync.WaitGroup
81
96
mq .mu .Lock ()
82
- if hs , ok := mq .handlers [mb .topic ]; ok {
83
- ctx , cancel := context .WithTimeout (mq .stopCtx , HandleTimeout )
97
+ hs , ok := mq .handlers [mb .topic ]
98
+ tmphs := make ([]Handler , 0 , len (hs ))
99
+ if ok {
84
100
for h := range hs {
85
- wg .Add (1 )
86
- go func (h Handler , ctx context.Context , body []byte ) {
87
- tracer := trace .GetTraceFromContext (ctx )
88
- defer wg .Done ()
89
-
90
- tmpCh := make (chan error , 1 )
91
- defer close (tmpCh )
92
- go func () {
93
- defer func () {
94
- if r := recover (); r != nil {
95
- tracer .Errorf ("panic: %v\n " , r )
96
- }
97
- }()
98
- tmpCh <- h .Handle (ctx , body )
99
- }()
101
+ tmphs = append (tmphs , h )
102
+ }
103
+ }
104
+ mq .mu .Unlock ()
105
+ defer handleBarrier .Done ()
100
106
101
- select {
102
- case <- tmpCh :
103
- case <- ctx .Done ():
107
+ var wg sync.WaitGroup
108
+ ctx , cancel := context .WithTimeout (mq .stopCtx , HandleTimeout )
109
+ defer cancel ()
110
+ for h := range tmphs {
111
+ wg .Add (1 )
112
+ go func (hd Handler , ctx context.Context , body []byte ) {
113
+ ctx = trace .WithTraceForContext (ctx , hd .Name ())
114
+ tracer := trace .GetTraceFromContext (ctx )
115
+ defer func () {
116
+ if r := recover (); r != nil {
117
+ tracer .Errorf ("handler %s panic: %v\n " , hd .Name (), r )
104
118
}
105
- }(h , ctx , mb .body )
106
- }
107
- mq .mu .Unlock ()
108
- wg .Wait ()
109
- cancel ()
110
- } else {
111
- mq .mu .Unlock ()
119
+ }()
120
+ defer wg .Done ()
121
+
122
+ tmpCh := make (chan error , 1 )
123
+ go func () {
124
+ defer func () {
125
+ if r := recover (); r != nil {
126
+ tracer .Errorf ("handler %s panic: %v\n " , hd .Name (), r )
127
+ }
128
+ }()
129
+ tmpCh <- hd .Handle (ctx , body )
130
+ }()
131
+
132
+ select {
133
+ case <- tmpCh :
134
+ case <- ctx .Done ():
135
+ }
136
+ }(tmphs [h ], ctx , mb .body )
112
137
}
138
+ wg .Wait ()
113
139
}
114
140
115
141
for {
@@ -118,7 +144,8 @@ func (mq *MsgQueue) Run() {
118
144
close (mq .data )
119
145
return
120
146
case msg := <- mq .data :
121
- handle (mq , & msg )
147
+ handleBarrier .Advance ()
148
+ go handle (mq , & msg )
122
149
}
123
150
}
124
151
}
0 commit comments