예제 #1
0
파일: job.go 프로젝트: jasonmoo/gearman-go
// Decode a job from byte slice
func decodeJob(data []byte) (job *Job, err error) {
	if len(data) < 12 {
		return nil, common.Errorf("Invalid data: %V", data)
	}
	datatype := common.BytesToUint32([4]byte{data[4], data[5], data[6], data[7]})
	l := common.BytesToUint32([4]byte{data[8], data[9], data[10], data[11]})
	if len(data[12:]) != int(l) {
		return nil, common.Errorf("Invalid data: %V", data)
	}
	data = data[12:]
	var handle string
	switch datatype {
	case common.WORK_DATA, common.WORK_WARNING, common.WORK_STATUS,
		common.WORK_COMPLETE, common.WORK_FAIL, common.WORK_EXCEPTION:
		i := bytes.IndexByte(data, '\x00')
		if i != -1 {
			handle = string(data[:i])
			data = data[i+1:]
		}
	}

	return &Job{magicCode: common.RES,
		DataType: datatype,
		Data:     data,
		Handle:   handle}, nil
}
예제 #2
0
파일: job.go 프로젝트: jasonmoo/gearman-go
// Decode job from byte slice
func decodeJob(data []byte) (job *Job, err error) {
	if len(data) < 12 {
		return nil, common.Errorf("Invalid data: %V", data)
	}
	datatype := common.BytesToUint32([4]byte{data[4], data[5], data[6], data[7]})
	l := common.BytesToUint32([4]byte{data[8], data[9], data[10], data[11]})
	if len(data[12:]) != int(l) {
		return nil, common.Errorf("Invalid data: %V", data)
	}
	data = data[12:]
	job = &Job{magicCode: common.RES, DataType: datatype, c: make(chan bool)}
	switch datatype {
	case common.JOB_ASSIGN:
		s := bytes.SplitN(data, []byte{'\x00'}, 3)
		if len(s) == 3 {
			job.Handle = string(s[0])
			job.Fn = string(s[1])
			data = s[2]
		}
	case common.JOB_ASSIGN_UNIQ:
		s := bytes.SplitN(data, []byte{'\x00'}, 4)
		if len(s) == 4 {
			job.Handle = string(s[0])
			job.Fn = string(s[1])
			job.UniqueId = string(s[2])
			data = s[3]
		}
	}
	job.Data = data
	return
}
예제 #3
0
// inputing loop
func (a *agent) inLoop() {
	defer func() {
		if r := recover(); r != nil {
			a.worker.err(common.Errorf("Exiting: %s", r))
		}
		close(a.in)
		close(a.out)
		a.worker.removeAgent(a)
	}()
	for a.worker.running {
		a.WriteJob(newJob(common.REQ, common.PRE_SLEEP, nil))
	RESTART:
		// got noop msg and in queue is zero, grab job
		rel, err := a.read()
		if err != nil {
			if err == common.ErrConnection {
				for a.worker.running {
					// if we lose connection, try to reconnect once a second forever
					if a.conn, err = net.Dial(common.NETWORK, a.addr); err != nil {
						a.worker.err(common.Errorf("Reconnection attempt failed.  Waiting to retry..."))
						<-time.After(time.Second)
						continue
					}
					goto RESTART
				}
				a.worker.err(err)
				break
			}
			a.worker.err(err)
			continue
		}
		job, err := decodeJob(rel)
		if err != nil {
			a.worker.err(err)
			continue
		}
		switch job.DataType {
		case common.NOOP:
			a.WriteJob(newJob(common.REQ, common.GRAB_JOB_UNIQ, nil))
		case common.ERROR, common.ECHO_RES, common.JOB_ASSIGN_UNIQ, common.JOB_ASSIGN:
			if a.worker.running {
				if a.worker.limit != nil {
					a.worker.limit <- true
				}
				job.agent = a
				a.worker.in <- job
			}
		}
	}
}
예제 #4
0
// Remove a function.
// Tell job servers 'I can not do this now' at the same time.
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)
	}
	return
}
예제 #5
0
// Add a function.
// Plz added job servers first, then functions.
// The API will tell every connected job server that 'I can do this'
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)
	}
	worker.funcs[funcname] = &jobFunc{f: f, timeout: timeout}

	if worker.running {
		worker.addFunc(funcname, timeout)
	}
	return
}
예제 #6
0
// status handler
func (client *Client) handleStatus(job *Job) {
	data := bytes.SplitN(job.Data, []byte{'\x00'}, 5)
	if len(data) != 5 {
		client.err(common.Errorf("Invalid data: %V", job.Data))
		return
	}
	status := &Status{}
	status.Handle = string(data[0])
	status.Known = (data[1][0] == '1')
	status.Running = (data[2][0] == '1')
	var err error
	status.Numerator, err = strconv.ParseUint(string(data[3]), 10, 0)
	if err != nil {
		client.err(common.Errorf("Invalid Integer: %s", data[3]))
		return
	}
	status.Denominator, err = strconv.ParseUint(string(data[4]), 10, 0)
	if err != nil {
		client.err(common.Errorf("Invalid Integer: %s", data[4]))
		return
	}
	client.status <- status
}
예제 #7
0
파일: job.go 프로젝트: jasonmoo/gearman-go
// Extract the job's result.
func (job *Job) Result() (data []byte, err error) {
	switch job.DataType {
	case common.WORK_FAIL:
		job.Handle = string(job.Data)
		return nil, common.ErrWorkFail
	case common.WORK_EXCEPTION:
		err = common.ErrWorkException
		fallthrough
	case common.WORK_COMPLETE:
		s := bytes.SplitN(job.Data, []byte{'\x00'}, 2)
		if len(s) != 2 {
			return nil, common.Errorf("Invalid data: %V", job.Data)
		}
		job.Handle = string(s[0])
		data = s[1]
	default:
		err = common.ErrDataType
	}
	return
}
예제 #8
0
// Execute the job. And send back the result.
func (worker *Worker) exec(job *Job) (err error) {
	defer func() {
		if r := recover(); r != nil {
			if e, ok := r.(error); ok {
				err = e
			} else {
				err = common.ErrUnknown
			}
		}
	}()
	f, ok := worker.funcs[job.Fn]
	if !ok {
		return common.Errorf("The function does not exist: %s", job.Fn)
	}
	var r *result
	if f.timeout == 0 {
		d, e := f.f(job)
		r = &result{data: d, err: e}
	} else {
		r = execTimeout(f.f, job, time.Duration(f.timeout)*time.Second)
	}
	var datatype uint32
	if r.err == nil {
		datatype = common.WORK_COMPLETE
	} else {
		if r.data == nil {
			datatype = common.WORK_FAIL
		} else {
			datatype = common.WORK_EXCEPTION
		}
		err = r.err
	}

	job.magicCode = common.REQ
	job.DataType = datatype
	job.Data = r.data
	if worker.running {
		job.agent.WriteJob(job)
	}
	return
}