Есть ли возможность прерывания горутина без паники? - PullRequest
1 голос
/ 14 мая 2019

Я настраиваю службу, предоставляю 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(...)
}

в этом сабезадание, журнал останавливается на определенной строке , и нет паники , нет ошибки , и отсрочка кажется не сработавшей, потому что блокировка мьютекса не разблокирована

журнал для другого задания исправен, а журнал задания следующего циклану тоже

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...