| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  | // Copyright 2011 Xing Xing <mikespook@gmail.com> All rights reserved.
 | 
					
						
							|  |  |  | // Use of this source code is governed by a MIT
 | 
					
						
							|  |  |  | // license that can be found in the LICENSE file.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package worker | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2012-06-05 14:36:39 +08:00
										 |  |  |     "time" | 
					
						
							| 
									
										
										
										
											2012-12-21 11:11:37 +08:00
										 |  |  |     "github.com/mikespook/gearman-go/common" | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-10 21:25:33 +08:00
										 |  |  | const ( | 
					
						
							| 
									
										
										
										
											2012-05-23 17:45:52 +08:00
										 |  |  |     Unlimited = 0 | 
					
						
							| 
									
										
										
										
											2012-05-10 21:25:33 +08:00
										 |  |  |     OneByOne = 1 | 
					
						
							| 
									
										
										
										
											2012-09-02 22:42:54 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     Immediately = 0 | 
					
						
							| 
									
										
										
										
											2012-05-10 21:25:33 +08:00
										 |  |  | ) | 
					
						
							| 
									
										
										
										
											2012-06-01 14:28:10 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | var ( | 
					
						
							|  |  |  |     ErrConnection = common.ErrConnection | 
					
						
							|  |  |  | ) | 
					
						
							| 
									
										
										
										
											2012-05-24 16:49:35 +08:00
										 |  |  | // Job handler
 | 
					
						
							|  |  |  | type JobHandler func(*Job) error | 
					
						
							| 
									
										
										
										
											2012-05-10 21:25:33 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-02 22:42:54 +08:00
										 |  |  | type JobFunc func(*Job) ([]byte, error) | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-24 16:49:35 +08:00
										 |  |  | // The definition of the callback function.
 | 
					
						
							|  |  |  | type jobFunc struct { | 
					
						
							|  |  |  |     f JobFunc | 
					
						
							|  |  |  |     timeout uint32 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  | // Map for added function.
 | 
					
						
							| 
									
										
										
										
											2012-05-24 16:49:35 +08:00
										 |  |  | type JobFuncs map[string]*jobFunc | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* | 
					
						
							| 
									
										
										
										
											2012-05-23 17:45:52 +08:00
										 |  |  | Worker side api for gearman | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | usage: | 
					
						
							| 
									
										
										
										
											2012-05-24 16:49:35 +08:00
										 |  |  | w = worker.New(worker.Unlimited) | 
					
						
							|  |  |  | w.AddFunction("foobar", foobar) | 
					
						
							|  |  |  | w.AddServer("127.0.0.1:4730") | 
					
						
							|  |  |  | w.Work() // Enter the worker's main loop
 | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | The definition of the callback function 'foobar' should suit for the type 'JobFunction'. | 
					
						
							|  |  |  | It looks like this: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-23 17:45:52 +08:00
										 |  |  | func foobar(job *Job) (data []byte, err os.Error) { | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  |     //sth. here
 | 
					
						
							|  |  |  |     //plaplapla...
 | 
					
						
							|  |  |  |     return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | type Worker struct { | 
					
						
							| 
									
										
										
										
											2012-05-24 16:49:35 +08:00
										 |  |  |     agents  []*agent | 
					
						
							| 
									
										
										
										
											2012-05-23 17:45:52 +08:00
										 |  |  |     funcs   JobFuncs | 
					
						
							|  |  |  |     in chan *Job | 
					
						
							|  |  |  |     running bool | 
					
						
							| 
									
										
										
										
											2012-05-10 21:25:33 +08:00
										 |  |  |     limit chan bool | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-23 17:45:52 +08:00
										 |  |  |     Id string | 
					
						
							| 
									
										
										
										
											2012-05-10 21:25:33 +08:00
										 |  |  |     // assign a ErrFunc to handle errors
 | 
					
						
							| 
									
										
										
										
											2012-05-23 17:45:52 +08:00
										 |  |  |     ErrHandler common.ErrorHandler | 
					
						
							| 
									
										
										
										
											2012-05-24 16:49:35 +08:00
										 |  |  |     JobHandler JobHandler | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Get a new worker
 | 
					
						
							| 
									
										
										
										
											2012-05-10 21:25:33 +08:00
										 |  |  | func New(l int) (worker *Worker) { | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  |     worker = &Worker{ | 
					
						
							| 
									
										
										
										
											2012-05-24 16:49:35 +08:00
										 |  |  |         agents: make([]*agent, 0), | 
					
						
							|  |  |  |         funcs: make(JobFuncs), | 
					
						
							| 
									
										
										
										
											2012-05-23 17:45:52 +08:00
										 |  |  |         in:  make(chan *Job, common.QUEUE_SIZE), | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-05-23 17:45:52 +08:00
										 |  |  |     if l != Unlimited { | 
					
						
							| 
									
										
										
										
											2012-05-10 21:25:33 +08:00
										 |  |  |         worker.limit = make(chan bool, l) | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  |     return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-10 21:25:33 +08:00
										 |  |  | // 
 | 
					
						
							|  |  |  | func (worker *Worker)err(e error) { | 
					
						
							| 
									
										
										
										
											2012-05-23 17:45:52 +08:00
										 |  |  |     if worker.ErrHandler != nil { | 
					
						
							|  |  |  |         worker.ErrHandler(e) | 
					
						
							| 
									
										
										
										
											2012-05-10 21:25:33 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  | // Add a server. The addr should be 'host:port' format.
 | 
					
						
							|  |  |  | // The connection is established at this time.
 | 
					
						
							|  |  |  | func (worker *Worker) AddServer(addr string) (err error) { | 
					
						
							|  |  |  |     // Create a new job server's client as a agent of server
 | 
					
						
							| 
									
										
										
										
											2012-05-24 16:49:35 +08:00
										 |  |  |     server, err := newAgent(addr, worker) | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  |     if err != nil { | 
					
						
							|  |  |  |         return err | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-05-24 16:49:35 +08:00
										 |  |  |     worker.agents = append(worker.agents, server) | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  |     return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-24 16:49:35 +08:00
										 |  |  | // Write a job to job server.
 | 
					
						
							|  |  |  | // Here, the job's mean is not the oraginal mean.
 | 
					
						
							|  |  |  | // Just looks like a network package for job's result or tell job server, there was a fail.
 | 
					
						
							|  |  |  | func (worker *Worker) broadcast(job *Job) { | 
					
						
							|  |  |  |     for _, v := range worker.agents { | 
					
						
							|  |  |  |         v.WriteJob(job) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  | // Add a function.
 | 
					
						
							|  |  |  | // Plz added job servers first, then functions.
 | 
					
						
							|  |  |  | // The API will tell every connected job server that 'I can do this'
 | 
					
						
							| 
									
										
										
										
											2012-05-24 16:49:35 +08:00
										 |  |  | func (worker *Worker) AddFunc(funcname string, | 
					
						
							|  |  |  | f JobFunc, timeout uint32) (err error) { | 
					
						
							|  |  |  |     if _, ok := worker.funcs[funcname]; ok { | 
					
						
							|  |  |  |         return common.Errorf("The function already exists: %s", funcname) | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-05-24 16:49:35 +08:00
										 |  |  |     worker.funcs[funcname] = &jobFunc{f: f, timeout: timeout} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if worker.running { | 
					
						
							|  |  |  |         worker.addFunc(funcname, timeout) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-24 16:49:35 +08:00
										 |  |  | // inner add function
 | 
					
						
							|  |  |  | func (worker *Worker) addFunc(funcname string, timeout uint32) { | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  |     var datatype uint32 | 
					
						
							|  |  |  |     var data []byte | 
					
						
							|  |  |  |     if timeout == 0 { | 
					
						
							| 
									
										
										
										
											2012-05-23 17:45:52 +08:00
										 |  |  |         datatype = common.CAN_DO | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  |         data = []byte(funcname) | 
					
						
							|  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2012-05-23 17:45:52 +08:00
										 |  |  |         datatype = common.CAN_DO_TIMEOUT | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  |         data = []byte(funcname + "\x00") | 
					
						
							| 
									
										
										
										
											2012-05-23 17:45:52 +08:00
										 |  |  |         t := common.Uint32ToBytes(timeout) | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  |         data = append(data, t[:]...) | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-05-23 17:45:52 +08:00
										 |  |  |     job := newJob(common.REQ, datatype, data) | 
					
						
							| 
									
										
										
										
											2012-05-24 16:49:35 +08:00
										 |  |  |     worker.broadcast(job) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Remove a function.
 | 
					
						
							|  |  |  | // Tell job servers 'I can not do this now' at the same time.
 | 
					
						
							| 
									
										
										
										
											2012-05-24 16:49:35 +08:00
										 |  |  | func (worker *Worker) RemoveFunc(funcname string) (err error) { | 
					
						
							|  |  |  |     if _, ok := worker.funcs[funcname]; !ok { | 
					
						
							|  |  |  |         return common.Errorf("The function does not exist: %s", funcname) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     delete(worker.funcs, funcname) | 
					
						
							|  |  |  |     if worker.running { | 
					
						
							|  |  |  |         worker.removeFunc(funcname) | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |     return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-24 16:49:35 +08:00
										 |  |  | // inner remove function
 | 
					
						
							|  |  |  | func (worker *Worker) removeFunc(funcname string) { | 
					
						
							|  |  |  |     job := newJob(common.REQ, common.CANT_DO, []byte(funcname)) | 
					
						
							|  |  |  |     worker.broadcast(job) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-29 23:54:20 +08:00
										 |  |  | func (worker *Worker) dealJob(job *Job) { | 
					
						
							|  |  |  |     defer func() { | 
					
						
							|  |  |  |         job.Close() | 
					
						
							| 
									
										
										
										
											2013-03-26 17:22:07 +08:00
										 |  |  |         if worker.running && worker.limit != nil { | 
					
						
							| 
									
										
										
										
											2013-04-24 16:58:06 +08:00
										 |  |  |             <-worker.limit | 
					
						
							| 
									
										
										
										
											2012-12-29 23:54:20 +08:00
										 |  |  |         } | 
					
						
							|  |  |  |     }() | 
					
						
							|  |  |  |     switch job.DataType { | 
					
						
							|  |  |  |     case common.ERROR: | 
					
						
							|  |  |  |         _, err := common.GetError(job.Data) | 
					
						
							|  |  |  |         worker.err(err) | 
					
						
							|  |  |  |     case common.JOB_ASSIGN, common.JOB_ASSIGN_UNIQ: | 
					
						
							|  |  |  |         if err := worker.exec(job); err != nil { | 
					
						
							|  |  |  |             worker.err(err) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         worker.handleJob(job) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  | // Main loop
 | 
					
						
							|  |  |  | func (worker *Worker) Work() { | 
					
						
							| 
									
										
										
										
											2012-05-24 16:49:35 +08:00
										 |  |  |     defer func() { | 
					
						
							| 
									
										
										
										
											2012-05-28 10:34:16 +08:00
										 |  |  |         for _, v := range worker.agents { | 
					
						
							|  |  |  |             v.Close() | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2012-05-24 16:49:35 +08:00
										 |  |  |     }() | 
					
						
							|  |  |  |     worker.running = true | 
					
						
							|  |  |  |     for _, v := range worker.agents { | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  |         go v.Work() | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2013-01-11 11:33:13 +08:00
										 |  |  |     for funcname, f := range worker.funcs { | 
					
						
							|  |  |  |         worker.addFunc(funcname, f.timeout) | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-05-24 16:49:35 +08:00
										 |  |  |     ok := true | 
					
						
							|  |  |  |     for ok { | 
					
						
							| 
									
										
										
										
											2012-11-21 17:53:49 +08:00
										 |  |  |         var job *Job | 
					
						
							| 
									
										
										
										
											2012-05-28 10:34:16 +08:00
										 |  |  |         if job, ok = <-worker.in; ok { | 
					
						
							| 
									
										
										
										
											2012-12-29 23:54:20 +08:00
										 |  |  |             go worker.dealJob(job) | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-24 16:49:35 +08:00
										 |  |  | // job handler
 | 
					
						
							|  |  |  | func (worker *Worker) handleJob(job *Job) { | 
					
						
							|  |  |  |     if worker.JobHandler != nil { | 
					
						
							|  |  |  |         if err := worker.JobHandler(job); err != nil { | 
					
						
							|  |  |  |             worker.err(err) | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-24 16:49:35 +08:00
										 |  |  | // Close.
 | 
					
						
							|  |  |  | func (worker *Worker) Close() { | 
					
						
							| 
									
										
										
										
											2013-03-26 17:22:07 +08:00
										 |  |  |     worker.running = false | 
					
						
							| 
									
										
										
										
											2012-05-24 16:49:35 +08:00
										 |  |  |     close(worker.in) | 
					
						
							|  |  |  |     if worker.limit != nil { | 
					
						
							|  |  |  |         close(worker.limit) | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Send a something out, get the samething back.
 | 
					
						
							| 
									
										
										
										
											2012-05-24 16:49:35 +08:00
										 |  |  | func (worker *Worker) Echo(data []byte) { | 
					
						
							| 
									
										
										
										
											2012-05-23 17:45:52 +08:00
										 |  |  |     job := newJob(common.REQ, common.ECHO_REQ, data) | 
					
						
							| 
									
										
										
										
											2012-05-24 16:49:35 +08:00
										 |  |  |     worker.broadcast(job) | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Remove all of functions.
 | 
					
						
							|  |  |  | // Both from the worker or job servers.
 | 
					
						
							| 
									
										
										
										
											2012-05-24 16:49:35 +08:00
										 |  |  | func (worker *Worker) Reset() { | 
					
						
							| 
									
										
										
										
											2012-05-23 17:45:52 +08:00
										 |  |  |     job := newJob(common.REQ, common.RESET_ABILITIES, nil) | 
					
						
							| 
									
										
										
										
											2012-05-24 16:49:35 +08:00
										 |  |  |     worker.broadcast(job) | 
					
						
							|  |  |  |     worker.funcs = make(JobFuncs) | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Set the worker's unique id.
 | 
					
						
							| 
									
										
										
										
											2012-05-24 16:49:35 +08:00
										 |  |  | func (worker *Worker) SetId(id string) { | 
					
						
							|  |  |  |     worker.Id = id | 
					
						
							| 
									
										
										
										
											2012-05-23 17:45:52 +08:00
										 |  |  |     job := newJob(common.REQ, common.SET_CLIENT_ID, []byte(id)) | 
					
						
							| 
									
										
										
										
											2012-05-24 16:49:35 +08:00
										 |  |  |     worker.broadcast(job) | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Execute the job. And send back the result.
 | 
					
						
							| 
									
										
										
										
											2012-05-23 17:45:52 +08:00
										 |  |  | func (worker *Worker) exec(job *Job) (err error) { | 
					
						
							| 
									
										
										
										
											2012-06-04 22:27:10 +08:00
										 |  |  |     defer func() { | 
					
						
							|  |  |  |         if r := recover(); r != nil { | 
					
						
							|  |  |  |             if e, ok := r.(error); ok { | 
					
						
							|  |  |  |                 err = e | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 err = common.ErrUnknown | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } () | 
					
						
							| 
									
										
										
										
											2013-04-23 16:58:06 +08:00
										 |  |  |     f, ok := worker.funcs[job.Fn] | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  |     if !ok { | 
					
						
							| 
									
										
										
										
											2013-04-23 16:58:06 +08:00
										 |  |  |         return common.Errorf("The function does not exist: %s", job.Fn) | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-09-02 22:42:54 +08:00
										 |  |  |     var r *result | 
					
						
							| 
									
										
										
										
											2012-08-30 16:12:15 +08:00
										 |  |  |     if f.timeout == 0 { | 
					
						
							| 
									
										
										
										
											2012-09-02 22:42:54 +08:00
										 |  |  |         d, e := f.f(job) | 
					
						
							|  |  |  |         r = &result{data:d, err: e} | 
					
						
							| 
									
										
										
										
											2012-08-30 16:12:15 +08:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2012-09-02 22:42:54 +08:00
										 |  |  |         r = execTimeout(f.f, job, time.Duration(f.timeout) * time.Second) | 
					
						
							| 
									
										
										
										
											2012-06-05 14:36:39 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  |     var datatype uint32 | 
					
						
							| 
									
										
										
										
											2012-06-05 14:36:39 +08:00
										 |  |  |     if r.err == nil { | 
					
						
							| 
									
										
										
										
											2012-05-23 17:45:52 +08:00
										 |  |  |         datatype = common.WORK_COMPLETE | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2012-06-05 14:36:39 +08:00
										 |  |  |         if r.data == nil { | 
					
						
							| 
									
										
										
										
											2012-05-23 17:45:52 +08:00
										 |  |  |             datatype = common.WORK_FAIL | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2012-05-23 17:45:52 +08:00
										 |  |  |             datatype = common.WORK_EXCEPTION | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2012-06-05 14:36:39 +08:00
										 |  |  |         err = r.err | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-23 17:45:52 +08:00
										 |  |  |     job.magicCode = common.REQ | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  |     job.DataType = datatype | 
					
						
							| 
									
										
										
										
											2012-06-05 14:36:39 +08:00
										 |  |  |     job.Data = r.data | 
					
						
							| 
									
										
										
										
											2013-03-26 17:22:07 +08:00
										 |  |  |     if worker.running { | 
					
						
							|  |  |  |         job.agent.WriteJob(job) | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-03-26 13:32:59 +08:00
										 |  |  |     return | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2012-05-24 16:49:35 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | func (worker *Worker) removeAgent(a *agent) { | 
					
						
							|  |  |  |     for k, v := range worker.agents { | 
					
						
							|  |  |  |         if v == a { | 
					
						
							|  |  |  |             worker.agents = append(worker.agents[:k], worker.agents[k + 1:] ...) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if len(worker.agents) == 0 { | 
					
						
							| 
									
										
										
										
											2012-05-28 10:34:16 +08:00
										 |  |  |         worker.err(common.ErrNoActiveAgent) | 
					
						
							| 
									
										
										
										
											2012-05-24 16:49:35 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2012-06-05 14:36:39 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | type result struct { | 
					
						
							|  |  |  |     data []byte | 
					
						
							|  |  |  |     err error | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2012-09-02 22:42:54 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 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() | 
					
						
							| 
									
										
										
										
											2013-04-23 16:58:06 +08:00
										 |  |  |         return &result{err:common.ErrTimeOut} | 
					
						
							| 
									
										
										
										
											2012-09-02 22:42:54 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |     return r | 
					
						
							|  |  |  | } |