albrow / jobs

A persistent and flexible background jobs library for go.
MIT License
499 stars 47 forks source link

job not exec with panic #28

Closed btfak closed 9 years ago

btfak commented 9 years ago

image

my code


var sche scheduler

type scheduler struct {
    tp           *jobs.Type
    golbalHeader map[string]string
}

func main() (err error) {
    tp, err := jobs.RegisterType(DEFAULT_JOB_TYPE, RETRY_TIMES, sche.getHandler())
    if err != nil {
        utils.Log().Error(err)
        return
    }
    sche.tp = tp
    pool, err := jobs.NewPool(nil)
    if err != nil {
        utils.Log().Error(err)
        return
    }
    defer func() {
        pool.Close()
        if err = pool.Wait(); err != nil {
            utils.Log().Error(err)
            return
        }
    }()
    if err = pool.Start(); err != nil {
        utils.Log().Error(err)
        return
    }
    return
}

... 

func (p *scheduler) getHandler() handler {
    return func(req *models.AddReq) error {
        utils.Log().Info("job start")
        post := gorequest.New().Post(req.Target)
        for k, v := range p.golbalHeader {
            post = post.Set(k, v)
        }
        for k, v := range req.Header {
            post = post.Set(k, v)
        }
        _, body, errs := post.Send(string(req.Body)).End()
        if len(errs) > 0 {
            utils.Log().Error(errs)
            return errs[0]
        }
        var rep response
        err := json.Unmarshal([]byte(body), &rep)
        if err != nil {
            utils.Log().Error(err)
            return err
        }
        if rep.Code != 0 {
            utils.Log().Error(rep.Code, rep.Message)
            return errors.New(rep.Message)
        }
        utils.Log().Info(rep)
        return nil
    }
}
albrow commented 9 years ago

@lubia, thank you for reporting this error. I want to track down what's wrong but i don't have enough information. Can you please give me the full stack trace? It would also help tremendously if you could provide complete, runnable example code.

btfak commented 9 years ago

here is sample code

btfak commented 9 years ago
package main

import (
    "fmt"
    "time"

    "github.com/albrow/jobs"
)

var sche *jobs.Type

func initJob() (err error) {
    sche, err = jobs.RegisterType("DEFAULT", 3, func(s string) (err error) {
        fmt.Println("exec at ", time.Now(), s)
        return
    })
    if err != nil {
        fmt.Println(err)
        return
    }
    return
}

func begin() (err error) {
    pool, err := jobs.NewPool(nil)
    if err != nil {
        fmt.Println(err)
        return
    }
    defer func() {
        pool.Close()
        if err = pool.Wait(); err != nil {
            fmt.Println(err)
            return
        }
    }()
    if err = pool.Start(); err != nil {
        fmt.Println(err)
        return
    }
    return
}

func add(s string) (err error) {
    // add a job exec after one second
    job, err := sche.Schedule(100, time.Now().Add(time.Second), s)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println(job.Id())
    return nil
}

func main() {
    err := initJob()
    if err != nil {
        fmt.Println(err)
        return
    }
    err = add("task 1")
    if err != nil {
        fmt.Println(err)
        return
    }
    err = begin()
    if err != nil {
        fmt.Println(err)
        return
    }
    err = add("task 2")
    if err != nil {
        fmt.Println(err)
        return
    }
    time.Sleep(time.Second * 3)
}

sometimes task1 execute,sometimes not. task 2 never execute.

btfak commented 9 years ago

this is data in redis, i work on mac osx 10.10.2, redis 2.8.19 64bit the sample code not panic now image image

albrow commented 9 years ago

@lubia, thank you for providing additional information. It seems like you are describing two different issues?

  1. The first issue you described had to do with unexpected panics. I cannot help you with this unless you give me more information about this specific issue.
  2. The second issue you described has to do with jobs not being executed. This is happening because the sample code you provided has a subtle bug. The defer statement schedules a function to be called immediately before the parent function returns. In the code you provided, the defer statement is inside the begin function. That means you are calling pool.Close just before the begin function returns and before the main function is done. Since the pool is being closed too early, sometimes not all the jobs are executed.

Here is a corrected version:

package main

import (
    "fmt"
    "time"

    "github.com/albrow/jobs"
)

var (
    sche *jobs.Type
    // I made pool a top-level variable so that was can access it inside of the main func.
    pool *jobs.Pool
)

func initJob() (err error) {
    sche, err = jobs.RegisterType("DEFAULT", 3, func(s string) (err error) {
        fmt.Println("exec at ", time.Now(), s)
        return
    })
    if err != nil {
        fmt.Println(err)
        return
    }
    return
}

func begin() (err error) {
    pool, err = jobs.NewPool(nil)
    if err != nil {
        fmt.Println(err)
        return
    }
    if err = pool.Start(); err != nil {
        fmt.Println(err)
        return
    }
    return
}

func add(s string) (err error) {
    // add a job exec after one second
    job, err := sche.Schedule(100, time.Now().Add(time.Second), s)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println(job.Id())
    return nil
}

func main() {
    err := initJob()
    if err != nil {
        fmt.Println(err)
        return
    }
    err = begin()
    if err != nil {
        fmt.Println(err)
        return
    }
    // The defer function is inside of main, so it will not run until main returns,
    // i.e. until the program exits. This is the behavior you want.
    defer func() {
        pool.Close()
        if err = pool.Wait(); err != nil {
            fmt.Println(err)
            return
        }
    }()
    err = add("task 1")
    if err != nil {
        fmt.Println(err)
        return
    }
    err = add("task 2")
    if err != nil {
        fmt.Println(err)
        return
    }
    time.Sleep(time.Second * 3)
}

The output of the above program is:

QLSgfODIb1Y9XTitax5ov0l8twyy
oOhZUUCRfgAD63v3ax5ov0l97v07
exec at  2015-07-20 20:10:04.951648096 -0700 PDT task 2
exec at  2015-07-20 20:10:05.156714793 -0700 PDT task 1

If you would like help with the first issue you described (unexpected panics), I need some more information. It would help if you could provide some sample code that causes an unexpected panic.

btfak commented 9 years ago

thank so much, help me a lot. sorry for the first issue, i can't get more infomation,because no log here, your package did not log anything.

btfak commented 9 years ago

The source code for first issue just like the code i paste above (second post) , just edit a little.

albrow commented 9 years ago

Great. You're welcome :) Closing this issue now.