fc/life_cycle_handler.go (59 lines of code) (raw):
// Copyright 2021 Alibaba Group Holding Limited. All Rights Reserved.
package fc
import (
"context"
"fmt"
"reflect"
)
// include initialize handler, pre-freeze handler and pre-stop handler
type LifeCycleHandler interface {
Invoke(ctx context.Context)
}
// fcLifeCycleHandler is the generic function type
type fcLifeCycleHandler func(context.Context)
// Invoke calls the handler, and serializes the response.
// If the underlying handler returned an error, or an error occurs during serialization, error is returned.
func (handler fcLifeCycleHandler) Invoke(ctx context.Context) {
handler(ctx)
}
func errorLifeCycleHandler(e error) fcLifeCycleHandler {
return func(ctx context.Context) {
panic(e)
}
}
func validateLifeCycleArguments(handler reflect.Type) error {
if handler.NumIn() != 1 {
return fmt.Errorf("life cycle handler should takes one arguments, but handler takes %d", handler.NumIn())
}
contextType := reflect.TypeOf((*context.Context)(nil)).Elem()
argumentType := handler.In(0)
if !argumentType.Implements(contextType) {
return fmt.Errorf("handler takes a single arguments, but it is not Context. got %s",
argumentType.Kind())
}
return nil
}
func validateLifeCycleReturns(handler reflect.Type) error {
if handler.NumOut() != 0 {
return fmt.Errorf("handler should not have a return value")
}
return nil
}
// NewLifeCycleHandler creates a http fc handler from the given handler function.
// The handler function parameter must satisfy the rules documented by RegisterInitializeHandler.
// If handlerFunc is not a valid handler, the returned Handler simply reports the validation error.
func NewLifeCycleHandler(handlerFunc interface{}) LifeCycleHandler {
if handlerFunc == nil {
return errorLifeCycleHandler(fmt.Errorf("handler is nil"))
}
handler := reflect.ValueOf(handlerFunc)
handlerType := reflect.TypeOf(handlerFunc)
if handlerType.Kind() != reflect.Func {
return errorLifeCycleHandler(fmt.Errorf("handler kind %s is not %s", handlerType.Kind(), reflect.Func))
}
err := validateLifeCycleArguments(handlerType)
if err != nil {
return errorLifeCycleHandler(err)
}
if err := validateLifeCycleReturns(handlerType); err != nil {
return errorLifeCycleHandler(err)
}
return fcLifeCycleHandler(func(ctx context.Context) {
handler.Call(
[]reflect.Value{
reflect.ValueOf(ctx),
})
})
}