@@ -32,7 +32,7 @@ Install both: | |||
log.Println(e) | |||
} | |||
w.AddServer("127.0.0.1:4730") | |||
w.AddFunc("ToUpper", ToUpper, 0) | |||
w.AddFunc("ToUpper", ToUpper, worker.Immediately) | |||
w.AddFunc("ToUpperTimeOut5", ToUpper, 5) | |||
w.Work() | |||
@@ -63,6 +63,7 @@ Xing Xing <mikespook@gmail.com> | |||
# History | |||
* 0.1.2 Fixed issues: timeout executing, resources leaking. | |||
* 0.1.1 Fixed the issue of grabbing jobs. | |||
* 0.1 Code refactoring; Redesign the API. | |||
* 0.0.1 Initial implementation, ugly code-style, slow profermance and unstable API. | |||
@@ -12,16 +12,26 @@ def check_request_status(job_request): | |||
def main(): | |||
client = gearman.GearmanClient(['localhost:4730', 'otherhost:4730']) | |||
completed_job_request = client.submit_job("ToUpper", "arbitrary binary data") | |||
check_request_status(completed_job_request) | |||
try: | |||
completed_job_request = client.submit_job("ToUpper", "arbitrary binary data") | |||
check_request_status(completed_job_request) | |||
except Exception as e: | |||
print type(e) | |||
completed_job_request = client.submit_job("ToUpperTimeOut5", "arbitrary binary data") | |||
check_request_status(completed_job_request) | |||
completed_job_request = client.submit_job("ToUpperTimeOut20", "arbitrary binary data") | |||
check_request_status(completed_job_request) | |||
try: | |||
completed_job_request = client.submit_job("ToUpperTimeOut5", "arbitrary binary data") | |||
check_request_status(completed_job_request) | |||
except Exception as e: | |||
print type(e) | |||
try: | |||
completed_job_request = client.submit_job("ToUpperTimeOut20", "arbitrary binary data") | |||
check_request_status(completed_job_request) | |||
except Exception as e: | |||
print type(e) | |||
if __name__ == '__main__': | |||
main() | |||
@@ -49,7 +49,7 @@ func main() { | |||
return nil | |||
} | |||
w.AddServer("127.0.0.1:4730") | |||
w.AddFunc("ToUpper", ToUpper, 0) | |||
w.AddFunc("ToUpper", ToUpper, worker.Immediately) | |||
w.AddFunc("ToUpperTimeOut5", ToUpperDelay10, 5) | |||
w.AddFunc("ToUpperTimeOut20", ToUpperDelay10, 20) | |||
go w.Work() | |||
@@ -91,12 +91,18 @@ func (job *Job) UpdateStatus(numerator, denominator int) { | |||
job.agent.WriteJob(newJob(common.REQ, common.WORK_STATUS, result)) | |||
} | |||
// close the job | |||
func (job *Job) Close() { | |||
close(job.c) | |||
} | |||
// cancel the job executing | |||
func (job *Job) cancel() { | |||
defer func() {recover()}() | |||
job.c <- true | |||
} | |||
// When a job was canceled, return a true form a channel | |||
func (job *Job) Canceled() chan bool { | |||
func (job *Job) Canceled() <-chan bool { | |||
return job.c | |||
} |
@@ -13,6 +13,8 @@ import ( | |||
const ( | |||
Unlimited = 0 | |||
OneByOne = 1 | |||
Immediately = 0 | |||
) | |||
var ( | |||
@@ -21,7 +23,7 @@ var ( | |||
// Job handler | |||
type JobHandler func(*Job) error | |||
type JobFunc func(job *Job) ([]byte, error) | |||
type JobFunc func(*Job) ([]byte, error) | |||
// The definition of the callback function. | |||
type jobFunc struct { | |||
@@ -179,21 +181,20 @@ func (worker *Worker) Work() { | |||
var job *Job | |||
for ok { | |||
if job, ok = <-worker.in; ok { | |||
switch job.DataType { | |||
case common.ERROR: | |||
go func() { | |||
go func() { | |||
defer job.Close() | |||
switch job.DataType { | |||
case common.ERROR: | |||
_, err := common.GetError(job.Data) | |||
worker.err(err) | |||
}() | |||
case common.JOB_ASSIGN, common.JOB_ASSIGN_UNIQ: | |||
go func() { | |||
case common.JOB_ASSIGN, common.JOB_ASSIGN_UNIQ: | |||
if err := worker.exec(job); err != nil { | |||
worker.err(err) | |||
} | |||
}() | |||
default: | |||
go worker.handleJob(job) | |||
} | |||
default: | |||
worker.handleJob(job) | |||
} | |||
}() | |||
} | |||
} | |||
} | |||
@@ -272,26 +273,12 @@ func (worker *Worker) exec(job *Job) (err error) { | |||
if !ok { | |||
return common.Errorf("The function does not exist: %s", funcname) | |||
} | |||
var r result | |||
var r *result | |||
if f.timeout == 0 { | |||
r.data, r.err = f.f(job) | |||
d, e := f.f(job) | |||
r = &result{data:d, err: e} | |||
} else { | |||
rslt := make(chan *result) | |||
defer close(rslt) | |||
go func() { | |||
defer func() {recover()}() | |||
var r result | |||
r.data, r.err = f.f(job) | |||
rslt <- &r | |||
}() | |||
select { | |||
case re := <-rslt: | |||
r.data = re.data | |||
r.err = re.err | |||
case <-time.After(time.Duration(f.timeout) * time.Second): | |||
r.err = common.ErrExecTimeOut | |||
job.cancel() | |||
} | |||
r = execTimeout(f.f, job, time.Duration(f.timeout) * time.Second) | |||
} | |||
var datatype uint32 | |||
if r.err == nil { | |||
@@ -327,3 +314,20 @@ type result struct { | |||
data []byte | |||
err error | |||
} | |||
func execTimeout(f JobFunc, job *Job, timeout time.Duration) (r *result) { | |||
rslt := make(chan *result) | |||
defer close(rslt) | |||
go func() { | |||
defer func() {recover()}() | |||
d, e := f(job) | |||
rslt <- &result{data: d, err: e} | |||
}() | |||
select { | |||
case r = <-rslt: | |||
case <-time.After(timeout): | |||
go job.cancel() | |||
return &result{err:common.ErrExecTimeOut} | |||
} | |||
return r | |||
} |