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  }