Я настраиваю службу, предоставляю http-сервер и запускаю goroutine, чтобы справиться с какой-то работой, посмотрим код
один раз в цикле, подзадача выглядит как прерывание after нет журналов после одной функциивызовите
ошибка не обнаружена, и задержка, по-видимому, не сработает, поскольку блокировка мьютекса не разблокирована
журнал не прерван или журнал другой работы завершен.нет перезапуска, выхода или oom kill в это время
это для CentOS 7.5, мой сервис работает в docker
go1.11 docker 18.09
это случайная ошибка, я добавляю больше log и открываю pprof, и пытаюсь воспроизвести эту ошибку
main.go
func main() {
....
// this is a cycle job, with custom time intervals
router.Cycle(r)
....
endless.ListenAndServe(":"+conf.Conf.Port, r)
}
router / cycle.go
// this is a loop job, when job end, sleep custom time intervals and run again
// implemented by encapsulating a goroutine, and create a context
func Cycle(g *gin.Engine) {
cyclec := cli.InitCycle(g)
cyclec.AddFunc(time.Second, schedule.RunSomeDeal)
cyclec.Start()
}
///RunSomeDeal
func RunSomeDeal(c *gin.Context) error {
...
// deal some sub job
for i := 0; i < missionLen; i++ {
// this is once job, like cycle but only run once
// a new context is generated by passing the exist context and a goroutine executes the callback function
helpers.Job.Run(c, func(newCtx *gin.Context) error {
return DealMission(newCtx, someparams...)
})
}
return nil
}
// Job.Run
func (c *Job) Run(ctx *gin.Context, f func(ctx *gin.Context) error) {
e := &Entry{
Job: FuncJob(f),
}
if c.getJobContext != nil {
e.span = c.getJobContext(ctx)
}
go c.runWithRecovery(e)
}
func (c *Job) runWithRecovery(e *Entry) {
ctx := gin.CreateNewContext(c.gin)
...
defer func() {
if r := recover(); r != nil {
const size = 64 << 10
buf := make([]byte, size)
buf = buf[:runtime.Stack(buf, false)]
requestId, _ := ctx.Get("requestId")
handleName := ctx.CustomContext.HandlerName()
info, _ := json.Marshal(map[string]interface{}{
...some kv for log
})
log.Printf(...)
}
gin.RecycleContext(c.gin, ctx)
}()
if c.beforeRun != nil {
ok := c.beforeRun(ctx, e.span)
if !ok {
return
}
}
error := e.Job.Run(ctx)
...
if c.afterRun != nil {
c.afterRun(ctx)
}
}
// DealMission
func DealMission(c *gin.Context, params...) {
// lock something use sync.mutex
doSomeLock()
defer func() {
// ...not trigger
unlockErr := unlockxxxxx(...)
if unlockErr != nil {
panic("some error info")
}
} ()
base.DebugLog(...)
err := SomeOtherFunc(c, params...)
base.DebugLog(...)
}
// some other func
func SomeOtherFunc(ctx *gin.Context, params...) error {
err := CallOther()
base.DebugLog(...)
err := CallOther()
base.DebugLog(...)
// there is no logs after this call func, and Job.runWithRecovery not catch any panic error
err := CallOther()
// print log...
base.DebugLog(...)
}
в этом сабезадание, журнал останавливается на определенной строке , и нет паники , нет ошибки , и отсрочка кажется не сработавшей, потому что блокировка мьютекса не разблокирована
журнал для другого задания исправен, а журнал задания следующего циклану тоже