#12 fixed
This commit is contained in:
parent
89ef28fb9b
commit
568c70b083
@ -82,16 +82,12 @@ func New(addr string) (client *Client, err error) {
|
|||||||
|
|
||||||
//
|
//
|
||||||
func (client *Client) connect() (err error) {
|
func (client *Client) connect() (err error) {
|
||||||
client.mutex.Lock()
|
|
||||||
defer client.mutex.Unlock()
|
|
||||||
client.conn, err = net.Dial(common.NETWORK, client.addr)
|
client.conn, err = net.Dial(common.NETWORK, client.addr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal write
|
// Internal write
|
||||||
func (client *Client) write(buf []byte) (err error) {
|
func (client *Client) write(buf []byte) (err error) {
|
||||||
client.mutex.RLock()
|
|
||||||
defer client.mutex.RUnlock()
|
|
||||||
var n int
|
var n int
|
||||||
for i := 0; i < len(buf); i += n {
|
for i := 0; i < len(buf); i += n {
|
||||||
n, err = client.conn.Write(buf[i:])
|
n, err = client.conn.Write(buf[i:])
|
||||||
@ -104,8 +100,6 @@ func (client *Client) write(buf []byte) (err error) {
|
|||||||
|
|
||||||
// read length bytes from the socket
|
// read length bytes from the socket
|
||||||
func (client *Client) readData(length int) (data []byte, err error) {
|
func (client *Client) readData(length int) (data []byte, err error) {
|
||||||
client.mutex.RLock()
|
|
||||||
defer client.mutex.RUnlock()
|
|
||||||
n := 0
|
n := 0
|
||||||
buf := make([]byte, common.BUFFER_SIZE)
|
buf := make([]byte, common.BUFFER_SIZE)
|
||||||
// read until data can be unpacked
|
// read until data can be unpacked
|
||||||
@ -236,9 +230,11 @@ func (client *Client) err (e error) {
|
|||||||
|
|
||||||
// job handler
|
// job handler
|
||||||
func (client *Client) handleJob(job *Job) {
|
func (client *Client) handleJob(job *Job) {
|
||||||
if h, ok := client.jobhandlers[job.UniqueId]; ok {
|
client.mutex.RLock()
|
||||||
|
defer client.mutex.RUnlock()
|
||||||
|
if h, ok := client.jobhandlers[job.Handle]; ok {
|
||||||
h(job)
|
h(job)
|
||||||
delete(client.jobhandlers, job.UniqueId)
|
delete(client.jobhandlers, job.Handle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,9 +312,11 @@ flag byte, jobhandler JobHandler) (handle string) {
|
|||||||
datatype = common.SUBMIT_JOB
|
datatype = common.SUBMIT_JOB
|
||||||
}
|
}
|
||||||
id := IdGen.Id()
|
id := IdGen.Id()
|
||||||
|
client.mutex.Lock()
|
||||||
|
defer client.mutex.Unlock()
|
||||||
handle = client.do(funcname, data, datatype, id)
|
handle = client.do(funcname, data, datatype, id)
|
||||||
if jobhandler != nil {
|
if jobhandler != nil {
|
||||||
client.jobhandlers[id] = jobhandler
|
client.jobhandlers[handle] = jobhandler
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -341,9 +339,13 @@ flag byte) (handle string) {
|
|||||||
|
|
||||||
// Get job status from job server.
|
// Get job status from job server.
|
||||||
// !!!Not fully tested.!!!
|
// !!!Not fully tested.!!!
|
||||||
func (client *Client) Status(handle string) (status *Status) {
|
func (client *Client) Status(handle string, timeout time.Duration) (status *Status, err error) {
|
||||||
client.writeJob(newJob(common.REQ, common.GET_STATUS, []byte(handle)))
|
client.writeJob(newJob(common.REQ, common.GET_STATUS, []byte(handle)))
|
||||||
status = <-client.status
|
select {
|
||||||
|
case status = <-client.status:
|
||||||
|
case <-time.NewTimer(timeout).C:
|
||||||
|
err = common.ErrTimeOut
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ type objectId struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (id *objectId) Id() string {
|
func (id *objectId) Id() string {
|
||||||
return id.String()
|
return id.Hex()
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewObjectId() IdGenerator {
|
func NewObjectId() IdGenerator {
|
||||||
|
@ -51,7 +51,6 @@ func decodeJob(data []byte) (job *Job, err error) {
|
|||||||
return nil, common.Errorf("Invalid data: %V", data)
|
return nil, common.Errorf("Invalid data: %V", data)
|
||||||
}
|
}
|
||||||
data = data[12:]
|
data = data[12:]
|
||||||
|
|
||||||
var handle string
|
var handle string
|
||||||
switch datatype {
|
switch datatype {
|
||||||
case common.WORK_DATA, common.WORK_WARNING, common.WORK_STATUS,
|
case common.WORK_DATA, common.WORK_WARNING, common.WORK_STATUS,
|
||||||
@ -59,7 +58,7 @@ func decodeJob(data []byte) (job *Job, err error) {
|
|||||||
i := bytes.IndexByte(data, '\x00')
|
i := bytes.IndexByte(data, '\x00')
|
||||||
if i != -1 {
|
if i != -1 {
|
||||||
handle = string(data[:i])
|
handle = string(data[:i])
|
||||||
data = data[i:]
|
data = data[i + 1:]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ package client
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
"errors"
|
"errors"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"github.com/mikespook/gearman-go/common"
|
"github.com/mikespook/gearman-go/common"
|
||||||
@ -115,9 +116,9 @@ flag byte) (addr, handle string) {
|
|||||||
|
|
||||||
// Get job status from job server.
|
// Get job status from job server.
|
||||||
// !!!Not fully tested.!!!
|
// !!!Not fully tested.!!!
|
||||||
func (pool *Pool) Status(addr, handle string) (status *Status, err error) {
|
func (pool *Pool) Status(addr, handle string, timeout time.Duration) (status *Status, err error) {
|
||||||
if client, ok := pool.clients[addr]; ok {
|
if client, ok := pool.clients[addr]; ok {
|
||||||
status = client.Status(handle)
|
status, err = client.Status(handle, timeout)
|
||||||
} else {
|
} else {
|
||||||
err = ErrNotFound
|
err = ErrNotFound
|
||||||
}
|
}
|
||||||
|
@ -24,8 +24,8 @@ var (
|
|||||||
ErrFuncNotFound = errors.New("The function was not found.")
|
ErrFuncNotFound = errors.New("The function was not found.")
|
||||||
ErrConnection = errors.New("Connection error.")
|
ErrConnection = errors.New("Connection error.")
|
||||||
ErrNoActiveAgent = errors.New("No active agent.")
|
ErrNoActiveAgent = errors.New("No active agent.")
|
||||||
ErrExecTimeOut = errors.New("Executing time out.")
|
ErrTimeOut = errors.New("Executing time out.")
|
||||||
ErrUnknown = errors.New("Unknown error.")
|
ErrUnknown = errors.New("Unknown error.")
|
||||||
)
|
)
|
||||||
func DisablePanic() {recover()}
|
func DisablePanic() {recover()}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
"github.com/mikespook/gearman-go/client"
|
"github.com/mikespook/gearman-go/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -11,7 +12,7 @@ func main() {
|
|||||||
// Set the autoinc id generator
|
// Set the autoinc id generator
|
||||||
// You can write your own id generator
|
// You can write your own id generator
|
||||||
// by implementing IdGenerator interface.
|
// by implementing IdGenerator interface.
|
||||||
client.IdGen = client.NewAutoIncId()
|
// client.IdGen = client.NewAutoIncId()
|
||||||
|
|
||||||
c, err := client.New("127.0.0.1:4730")
|
c, err := client.New("127.0.0.1:4730")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -20,20 +21,22 @@ func main() {
|
|||||||
defer c.Close()
|
defer c.Close()
|
||||||
c.ErrHandler = func(e error) {
|
c.ErrHandler = func(e error) {
|
||||||
log.Println(e)
|
log.Println(e)
|
||||||
panic(e)
|
|
||||||
}
|
}
|
||||||
echo := []byte("Hello\x00 world")
|
echo := []byte("Hello\x00 world")
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
c.Echo(echo)
|
log.Println(string(c.Echo(echo)))
|
||||||
wg.Add(1)
|
wg.Done()
|
||||||
jobHandler := func(job *client.Job) {
|
jobHandler := func(job *client.Job) {
|
||||||
log.Printf("%s", job.Data)
|
log.Printf("%s", job.Data)
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}
|
}
|
||||||
handle := c.Do("ToUpper", echo, client.JOB_NORMAL, jobHandler)
|
handle := c.Do("ToUpper", echo, client.JOB_NORMAL, jobHandler)
|
||||||
|
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
log.Printf("%t", c.Status(handle))
|
status, err := c.Status(handle, time.Second)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
log.Printf("%t", status)
|
||||||
|
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
@ -10,9 +10,7 @@ The protocol was implemented by native way.
|
|||||||
package gearman
|
package gearman
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"time"
|
"time"
|
||||||
"errors"
|
|
||||||
"testing"
|
"testing"
|
||||||
"strings"
|
"strings"
|
||||||
"github.com/mikespook/gearman-go/client"
|
"github.com/mikespook/gearman-go/client"
|
||||||
@ -21,7 +19,6 @@ import (
|
|||||||
|
|
||||||
const(
|
const(
|
||||||
STR = "The gearman-go is a pure go implemented library."
|
STR = "The gearman-go is a pure go implemented library."
|
||||||
UPPERSTR = "THE GEARMAN-GO IS A PURE GO IMPLEMENTED LIRBRARY."
|
|
||||||
GEARMAND = "127.0.0.1:4730"
|
GEARMAND = "127.0.0.1:4730"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -51,6 +48,10 @@ func TestJobs(t *testing.T) {
|
|||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
w.ErrHandler = func(e error) {
|
||||||
|
t.Error(e)
|
||||||
|
}
|
||||||
go w.Work()
|
go w.Work()
|
||||||
|
|
||||||
c, err := client.New(GEARMAND)
|
c, err := client.New(GEARMAND)
|
||||||
@ -61,29 +62,37 @@ func TestJobs(t *testing.T) {
|
|||||||
defer c.Close()
|
defer c.Close()
|
||||||
|
|
||||||
c.ErrHandler = func(e error) {
|
c.ErrHandler = func(e error) {
|
||||||
panic(e)
|
t.Error(e)
|
||||||
}
|
|
||||||
|
|
||||||
jobHandler := func(job *client.Job) {
|
|
||||||
if (string(job.Data) != UPPERSTR) {
|
|
||||||
panic(errors.New(fmt.Sprintf("%s expected, got %s", UPPERSTR, job.Data)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
jobHandler := func(job *client.Job) {
|
||||||
|
upper := strings.ToUpper(STR)
|
||||||
|
if (string(job.Data) != upper) {
|
||||||
|
t.Error("%s expected, got %s", []byte(upper), job.Data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
handle := c.Do("ToUpper", []byte(STR), client.JOB_NORMAL, jobHandler)
|
handle := c.Do("ToUpper", []byte(STR), client.JOB_NORMAL, jobHandler)
|
||||||
status := c.Status(handle)
|
status, err := c.Status(handle, time.Second)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if !status.Known {
|
if !status.Known {
|
||||||
t.Errorf("%s should be known", status.Handle)
|
t.Errorf("%s should be known", status.Handle)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
handle := c.DoBg("Sleep", nil, client.JOB_NORMAL)
|
handle := c.DoBg("Sleep", nil, client.JOB_NORMAL)
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
status := c.Status(handle)
|
status, err := c.Status(handle, time.Second)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if !status.Known {
|
if !status.Known {
|
||||||
t.Errorf("%s should be known", status.Handle)
|
t.Errorf("%s should be known", status.Handle)
|
||||||
@ -91,7 +100,23 @@ func TestJobs(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !status.Running {
|
if !status.Running {
|
||||||
t.Errorf("%s shouldn be running", status.Handle)
|
t.Errorf("%s should be running", status.Handle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
status, err := c.Status("not exists handle", time.Second)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if status.Known {
|
||||||
|
t.Errorf("%s shouldn't be known", status.Handle)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if status.Running {
|
||||||
|
t.Errorf("%s shouldn't be running", status.Handle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
package worker
|
package worker
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"strconv"
|
"strconv"
|
||||||
"github.com/mikespook/gearman-go/common"
|
"github.com/mikespook/gearman-go/common"
|
||||||
)
|
)
|
||||||
@ -13,7 +14,7 @@ import (
|
|||||||
// Worker side job
|
// Worker side job
|
||||||
type Job struct {
|
type Job struct {
|
||||||
Data []byte
|
Data []byte
|
||||||
Handle, UniqueId string
|
Handle, UniqueId, Fn string
|
||||||
agent *agent
|
agent *agent
|
||||||
magicCode, DataType uint32
|
magicCode, DataType uint32
|
||||||
c chan bool
|
c chan bool
|
||||||
@ -24,8 +25,7 @@ func newJob(magiccode, datatype uint32, data []byte) (job *Job) {
|
|||||||
return &Job{magicCode: magiccode,
|
return &Job{magicCode: magiccode,
|
||||||
DataType: datatype,
|
DataType: datatype,
|
||||||
Data: data,
|
Data: data,
|
||||||
c: make(chan bool),
|
c: make(chan bool),}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode job from byte slice
|
// Decode job from byte slice
|
||||||
@ -39,7 +39,25 @@ func decodeJob(data []byte) (job *Job, err error) {
|
|||||||
return nil, common.Errorf("Invalid data: %V", data)
|
return nil, common.Errorf("Invalid data: %V", data)
|
||||||
}
|
}
|
||||||
data = data[12:]
|
data = data[12:]
|
||||||
job = newJob(common.RES, datatype, data)
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ package worker
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
"bytes"
|
|
||||||
"github.com/mikespook/gearman-go/common"
|
"github.com/mikespook/gearman-go/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -258,24 +257,9 @@ func (worker *Worker) exec(job *Job) (err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} ()
|
} ()
|
||||||
var limit int
|
f, ok := worker.funcs[job.Fn]
|
||||||
if job.DataType == common.JOB_ASSIGN {
|
|
||||||
limit = 3
|
|
||||||
} else {
|
|
||||||
limit = 4
|
|
||||||
}
|
|
||||||
jobdata := bytes.SplitN(job.Data, []byte{'\x00'}, limit)
|
|
||||||
job.Handle = string(jobdata[0])
|
|
||||||
funcname := string(jobdata[1])
|
|
||||||
if job.DataType == common.JOB_ASSIGN {
|
|
||||||
job.Data = jobdata[2]
|
|
||||||
} else {
|
|
||||||
job.UniqueId = string(jobdata[2])
|
|
||||||
job.Data = jobdata[3]
|
|
||||||
}
|
|
||||||
f, ok := worker.funcs[funcname]
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return common.Errorf("The function does not exist: %s", funcname)
|
return common.Errorf("The function does not exist: %s", job.Fn)
|
||||||
}
|
}
|
||||||
var r *result
|
var r *result
|
||||||
if f.timeout == 0 {
|
if f.timeout == 0 {
|
||||||
@ -333,7 +317,7 @@ func execTimeout(f JobFunc, job *Job, timeout time.Duration) (r *result) {
|
|||||||
case r = <-rslt:
|
case r = <-rslt:
|
||||||
case <-time.After(timeout):
|
case <-time.After(timeout):
|
||||||
go job.cancel()
|
go job.cancel()
|
||||||
return &result{err:common.ErrExecTimeOut}
|
return &result{err:common.ErrTimeOut}
|
||||||
}
|
}
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user