core/base/entry.go (83 lines of code) (raw):

// Copyright 1999-2020 Alibaba Group Holding Ltd. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package base import ( "sync" "github.com/pkg/errors" "github.com/alibaba/sentinel-golang/logging" ) type ExitHandler func(entry *SentinelEntry, ctx *EntryContext) error type SentinelEntry struct { res *ResourceWrapper // one entry bounds with one context ctx *EntryContext exitHandlers []ExitHandler // each entry holds a slot chain. // it means this entry will go through the sc sc *SlotChain exitCtl sync.Once } func NewSentinelEntry(ctx *EntryContext, rw *ResourceWrapper, sc *SlotChain) *SentinelEntry { return &SentinelEntry{ res: rw, ctx: ctx, exitHandlers: make([]ExitHandler, 0), sc: sc, } } func (e *SentinelEntry) WhenExit(exitHandler ExitHandler) { e.exitHandlers = append(e.exitHandlers, exitHandler) } func (e *SentinelEntry) SetError(err error) { if e.ctx != nil { e.ctx.SetError(err) } } func (e *SentinelEntry) SetPair(key, val interface{}) { if e.ctx != nil { e.ctx.SetPair(key, val) } } func (e *SentinelEntry) Context() *EntryContext { return e.ctx } func (e *SentinelEntry) Resource() *ResourceWrapper { return e.res } type ExitOptions struct { err error } type ExitOption func(*ExitOptions) func WithError(err error) ExitOption { return func(opts *ExitOptions) { opts.err = err } } func (e *SentinelEntry) Exit(exitOps ...ExitOption) { var options = ExitOptions{ err: nil, } for _, opt := range exitOps { opt(&options) } ctx := e.ctx if ctx == nil { return } if options.err != nil { ctx.SetError(options.err) } e.exitCtl.Do(func() { defer func() { if err := recover(); err != nil { logging.Error(errors.Errorf("%+v", err), "Sentinel internal panic in SentinelEntry.Exit()") } if e.sc != nil { e.sc.RefurbishContext(ctx) } }() for _, handler := range e.exitHandlers { if err := handler(e, ctx); err != nil { logging.Error(err, "Fail to execute exitHandler in SentinelEntry.Exit()", "resource", e.Resource().Name()) } } if e.sc != nil { e.sc.exit(ctx) } }) }