github.com/weedge/lib@v0.0.0-20230424045628-a36dcc1d90e4/chain/handler.go (about) 1 package chain 2 3 import ( 4 "fmt" 5 "reflect" 6 "sort" 7 "strings" 8 "sync" 9 "time" 10 11 "github.com/weedge/lib/log" 12 ) 13 14 type ICtx interface { 15 ValidateData() (err error) 16 } 17 type HandleFunc func() error 18 type HandleCtxFunc func(ctx ICtx) error 19 20 type Handler struct { 21 IsPass bool 22 Name string 23 Cost int64 24 Handle HandleFunc 25 CtxHandle HandleCtxFunc 26 ReflectValue reflect.Value 27 Status int 28 } 29 30 func NewHandler(isPass bool, name string, funcHandle HandleFunc) Handler { 31 return Handler{IsPass: isPass, Name: name, Handle: funcHandle} 32 } 33 34 func NewCtxHandler(isPass bool, name string, funcHandle HandleCtxFunc) Handler { 35 return Handler{IsPass: isPass, Name: name, CtxHandle: funcHandle} 36 } 37 38 func NewReflectHandler(isPass bool, name string, reflectValue reflect.Value) Handler { 39 return Handler{IsPass: isPass, Name: name, ReflectValue: reflectValue} 40 } 41 42 type Handlers []Handler 43 44 func (s Handlers) Len() int { return len(s) } 45 func (s Handlers) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 46 func (s Handlers) Less(i, j int) bool { return s[i].Cost < s[j].Cost } 47 48 type ConcurrencyHandlers struct { 49 Concurrency bool 50 Handlers Handlers 51 } 52 53 func NewConcurrencyHandlers(concurrency bool, handlers Handlers) *ConcurrencyHandlers { 54 return &ConcurrencyHandlers{Concurrency: concurrency, Handlers: handlers} 55 } 56 57 func (m *ConcurrencyHandlers) RunHandler() (err error) { 58 if m.Concurrency { 59 return m.Handlers.ConcurrencyRunHandler() 60 } 61 62 return m.Handlers.RunHandler() 63 } 64 65 func (m *ConcurrencyHandlers) RunCtxHandler(ctx ICtx) (err error) { 66 if m.Concurrency { 67 return m.Handlers.ConcurrencyRunCtxHandler(ctx) 68 } 69 70 return m.Handlers.RunCtxHandler(ctx) 71 } 72 73 func (m *ConcurrencyHandlers) FormatCost() (str string) { 74 var buf strings.Builder 75 76 if m.Concurrency { 77 buf.WriteString("concurrency:") 78 buf.WriteString(m.Handlers.FormatMaxCost()) 79 } else { 80 buf.WriteString(m.Handlers.FormatCost()) 81 } 82 83 return buf.String() 84 } 85 86 func (m *Handlers) AddHandler(handler ...Handler) { 87 *m = append(*m, handler...) 88 } 89 90 func (m *Handlers) RunCtxHandler(ctx ICtx) (err error) { 91 err = ctx.ValidateData() 92 if err != nil { 93 return 94 } 95 for index, item := range *m { 96 preTime := time.Now().UnixNano() 97 (*m)[index].Status = PROCESS_STATUS_DOING 98 err = item.CtxHandle(ctx) 99 (*m)[index].Cost = (time.Now().UnixNano() - preTime) / 1000000 100 if err != nil { 101 (*m)[index].Status = PROCESS_STATUS_FAIL 102 log.Errorf("%s process ctx[%v] err[%s]", item.Name, ctx, err.Error()) 103 if !item.IsPass { 104 err = fmt.Errorf("%s process ctx[%v] err[%s]", item.Name, ctx, err.Error()) 105 return 106 } 107 log.Infof("%s process ctx[%v] error[%s] pass", item.Name, ctx, err.Error()) 108 } else { 109 (*m)[index].Status = PROCESS_STATUS_OK 110 log.Infof("%s process ctx[%v] ok", item.Name, ctx) 111 } 112 } 113 114 return 115 } 116 117 func (m *Handlers) RunHandler() (err error) { 118 for index, item := range *m { 119 preTime := time.Now().UnixNano() 120 (*m)[index].Status = PROCESS_STATUS_DOING 121 err = item.Handle() 122 (*m)[index].Cost = (time.Now().UnixNano() - preTime) / 1000000 123 if err != nil { 124 (*m)[index].Status = PROCESS_STATUS_FAIL 125 log.Errorf("%s process err[%s]", item.Name, err.Error()) 126 if !item.IsPass { 127 err = fmt.Errorf("%s process err[%s]", item.Name, err.Error()) 128 return 129 } 130 log.Infof("%s process error[%s] pass", item.Name, err.Error()) 131 } else { 132 (*m)[index].Status = PROCESS_STATUS_OK 133 log.Infof("%s process ok", item.Name) 134 } 135 } 136 137 return 138 } 139 140 func (m *Handlers) ConcurrencyRunCtxHandler(ctx ICtx) (err error) { 141 err = ctx.ValidateData() 142 if err != nil { 143 return 144 } 145 var wg sync.WaitGroup 146 for index, item := range *m { 147 wg.Add(1) 148 go func(wg *sync.WaitGroup, index int, item Handler) { 149 defer wg.Done() 150 preTime := time.Now().UnixNano() 151 (*m)[index].Status = PROCESS_STATUS_DOING 152 localErr := item.CtxHandle(ctx) 153 (*m)[index].Cost = int64((time.Now().UnixNano() - preTime) / 1000000) 154 if localErr != nil { 155 (*m)[index].Status = PROCESS_STATUS_FAIL 156 log.Errorf("%s process ctx[%v] err[%s]", item.Name, ctx, localErr.Error()) 157 if !item.IsPass { 158 err = fmt.Errorf("%s process ctx[%v] err[%s]", item.Name, ctx, err.Error()) 159 return 160 } 161 log.Infof("%s process ctx[%v] error[%s] pass", item.Name, ctx, localErr.Error()) 162 } else { 163 (*m)[index].Status = PROCESS_STATUS_OK 164 log.Infof("%s process ctx[%v] ok", item.Name, ctx) 165 } 166 }(&wg, index, item) 167 } 168 wg.Wait() 169 170 return 171 } 172 173 func (m *Handlers) ConcurrencyRunHandler() (err error) { 174 var wg sync.WaitGroup 175 for index, item := range *m { 176 wg.Add(1) 177 go func(wg *sync.WaitGroup, index int, item Handler) { 178 defer wg.Done() 179 preTime := time.Now().UnixNano() 180 (*m)[index].Status = PROCESS_STATUS_DOING 181 err = item.Handle() 182 (*m)[index].Cost = int64((time.Now().UnixNano() - preTime) / 1000000) 183 if err != nil { 184 (*m)[index].Status = PROCESS_STATUS_FAIL 185 log.Errorf("%s process err[%s]", item.Name, err.Error()) 186 if !item.IsPass { 187 err = fmt.Errorf("%s process err[%s]", item.Name, err.Error()) 188 return 189 } 190 log.Infof("%s process error[%s] pass", item.Name, err.Error()) 191 } else { 192 (*m)[index].Status = PROCESS_STATUS_OK 193 log.Infof("%s process ok", item.Name) 194 } 195 }(&wg, index, item) 196 } 197 wg.Wait() 198 199 return 200 } 201 202 func (m *Handlers) RunReflectValueCall() (err error) { 203 for index, item := range *m { 204 preTime := time.Now().UnixNano() 205 (*m)[index].Status = PROCESS_STATUS_DOING 206 reflectValues := item.ReflectValue.Call([]reflect.Value{}) 207 (*m)[index].Cost = int64((time.Now().UnixNano() - preTime) / 1000000) 208 if len(reflectValues) == 0 { 209 (*m)[index].Status = PROCESS_STATUS_FAIL 210 err = fmt.Errorf("refect value len is empty") 211 return 212 } 213 var ok bool 214 err, ok = reflectValues[0].Interface().(error) 215 if ok { 216 (*m)[index].Status = PROCESS_STATUS_FAIL 217 log.Errorf("%s process err[%s]", item.Name, err.Error()) 218 if !item.IsPass { 219 err = fmt.Errorf("%s process err[%s]", item.Name, err.Error()) 220 return 221 } 222 log.Infof("%s process error[%s] pass", item.Name, err.Error()) 223 } else { 224 (*m)[index].Status = PROCESS_STATUS_OK 225 log.Infof("%s process ok", item.Name) 226 } 227 } 228 229 return 230 } 231 232 func (m *Handlers) FormatCost() (str string) { 233 totalCost := int64(0) 234 for _, item := range *m { 235 str += fmt.Sprintf("%s_pass[%t]_status[%d]_cost[%d]->", item.Name, item.IsPass, item.Status, item.Cost) 236 totalCost += item.Cost 237 } 238 str += fmt.Sprintf("totalCost:%d", totalCost) 239 return 240 } 241 242 func (m *Handlers) FormatMaxCost() (str string) { 243 sort.Sort(m) 244 for _, item := range *m { 245 str += fmt.Sprintf("%s_pass[%t]_status[%d]_cost[%d]||", item.Name, item.IsPass, item.Status, item.Cost) 246 } 247 str += fmt.Sprintf("totalCost:%d", (*m)[m.Len()-1].Cost) 248 return 249 }