forked from yuxh/gearman-go
The client can work now...with some known bugs. :(
This commit is contained in:
parent
c5b9f19962
commit
016dd669aa
@ -9,7 +9,7 @@ TARG=gearman
|
||||
# GOFILES=\
|
||||
# worker.go\
|
||||
|
||||
CLEANFILES+= worker
|
||||
CLEANFILES+= worker client
|
||||
|
||||
include $(GOROOT)/src/Make.pkg
|
||||
|
||||
|
40
example/client.go
Normal file
40
example/client.go
Normal file
@ -0,0 +1,40 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"gearman"
|
||||
"log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
client := gearman.NewClient()
|
||||
defer client.Close()
|
||||
client.AddServer("127.0.0.1:4730")
|
||||
echo := []byte("Hello world")
|
||||
log.Println(echo)
|
||||
log.Println(client.Echo(echo))
|
||||
|
||||
handle, err := client.Do("ToUpper", echo, gearman.JOB_HIGH)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
known, running, numerator, denominator, err := client.Status(handle)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
if !known {
|
||||
log.Println("Unknown")
|
||||
}
|
||||
if running {
|
||||
log.Printf("%g%%\n", float32(numerator) * 100 / float32(denominator))
|
||||
} else {
|
||||
log.Println("Not running")
|
||||
}
|
||||
log.Println("read")
|
||||
if job, err := client.ReadJob(); err != nil {
|
||||
log.Println(err)
|
||||
} else {
|
||||
data, err := job.Result();
|
||||
log.Println(err)
|
||||
log.Println(data)
|
||||
}
|
||||
}
|
@ -3,20 +3,19 @@ package gearman
|
||||
import (
|
||||
"os"
|
||||
"net"
|
||||
// "log"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
mutex sync.Mutex
|
||||
conn net.Conn
|
||||
running bool
|
||||
JobQueue chan *ClientJob
|
||||
ErrQueue chan os.Error
|
||||
UId uint32
|
||||
}
|
||||
|
||||
func NewClient() (client * Client){
|
||||
client = &Client{running:false,
|
||||
JobQueue:make(chan *ClientJob, QUEUE_CAP),
|
||||
ErrQueue:make(chan os.Error, QUEUE_CAP),}
|
||||
client = &Client{JobQueue:make(chan *ClientJob, QUEUE_CAP),
|
||||
UId:1}
|
||||
return
|
||||
}
|
||||
|
||||
@ -26,49 +25,42 @@ func (client *Client) AddServer(addr string) (err os.Error) {
|
||||
return
|
||||
}
|
||||
client.conn = conn
|
||||
go client.work()
|
||||
return
|
||||
}
|
||||
|
||||
func (client *Client) work() {
|
||||
OUT: for client.running {
|
||||
var rel []byte
|
||||
for {
|
||||
buf := make([]byte, 2048)
|
||||
n, err := client.conn.Read(buf)
|
||||
if err != nil {
|
||||
if err == os.EOF && n == 0 {
|
||||
break
|
||||
}
|
||||
client.ErrQueue <- err
|
||||
continue OUT
|
||||
func (client *Client) ReadJob() (job *ClientJob, err os.Error) {
|
||||
var rel []byte
|
||||
for {
|
||||
buf := make([]byte, BUFFER_SIZE)
|
||||
var n int
|
||||
if n, err = client.conn.Read(buf); err != nil {
|
||||
if (err == os.EOF && n == 0) {
|
||||
break
|
||||
}
|
||||
rel = append(rel, buf[0: n] ...)
|
||||
return
|
||||
}
|
||||
job, err := DecodeClientJob(rel)
|
||||
if err != nil {
|
||||
client.ErrQueue <- err
|
||||
} else {
|
||||
switch(job.dataType) {
|
||||
case ERROR:
|
||||
_, err := getError(job.Data)
|
||||
client.ErrQueue <- err
|
||||
case ECHO_RES:
|
||||
client.JobQueue <- job
|
||||
}
|
||||
rel = append(rel, buf[0: n] ...)
|
||||
if n < BUFFER_SIZE {
|
||||
break
|
||||
}
|
||||
}
|
||||
if job, err = DecodeClientJob(rel); err != nil {
|
||||
return
|
||||
} else {
|
||||
switch(job.dataType) {
|
||||
case ERROR:
|
||||
_, err = getError(job.Data)
|
||||
return
|
||||
case WORK_DATA, WORK_WARNING, WORK_STATUS, WORK_COMPLETE, WORK_FAIL, WORK_EXCEPTION:
|
||||
client.JobQueue <- job
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (client *Client) Do(funcname string, data []byte, flag byte) (err os.Error) {
|
||||
func (client *Client) Do(funcname string, data []byte, flag byte) (handle string, err os.Error) {
|
||||
var datatype uint32
|
||||
if flag & JOB_NORMAL == JOB_NORMAL {
|
||||
if flag & JOB_BG == JOB_BG {
|
||||
datatype = SUBMIT_JOB_BG
|
||||
} else {
|
||||
datatype = SUBMIT_JOB
|
||||
}
|
||||
} else if flag & JOB_LOW == JOB_LOW {
|
||||
if flag & JOB_LOW == JOB_LOW {
|
||||
if flag & JOB_BG == JOB_BG {
|
||||
datatype = SUBMIT_JOB_LOW_BG
|
||||
} else {
|
||||
@ -80,20 +72,97 @@ func (client *Client) Do(funcname string, data []byte, flag byte) (err os.Error)
|
||||
} else {
|
||||
datatype = SUBMIT_JOB_HIGH
|
||||
}
|
||||
} else if flag & JOB_BG == JOB_BG {
|
||||
datatype = SUBMIT_JOB_BG
|
||||
} else {
|
||||
datatype = SUBMIT_JOB
|
||||
}
|
||||
|
||||
rel := make([]byte, 0, 1024 * 64)
|
||||
rel = append(rel, []byte(funcname) ...)
|
||||
rel = append(rel, '\x00')
|
||||
rel = append(rel, '\xFF')
|
||||
client.mutex.Lock()
|
||||
uid := uint32ToByte(client.UId)
|
||||
client.UId ++
|
||||
rel = append(rel, uid[:] ...)
|
||||
client.mutex.Unlock()
|
||||
rel = append(rel, '\x00')
|
||||
rel = append(rel, data ...)
|
||||
job := NewClientJob(REQ, datatype, data)
|
||||
return client.WriteJob(job)
|
||||
if err = client.WriteJob(NewClientJob(REQ, datatype, rel)); err != nil {
|
||||
return
|
||||
}
|
||||
var job *ClientJob
|
||||
if job, err = client.ReadLastJob(JOB_CREATED); err != nil {
|
||||
return
|
||||
}
|
||||
handle = string(job.Data)
|
||||
go func() {
|
||||
if flag & JOB_BG != JOB_BG {
|
||||
for {
|
||||
if job, err = client.ReadJob(); err != nil {
|
||||
return
|
||||
}
|
||||
switch job.dataType {
|
||||
case WORK_DATA, WORK_WARNING:
|
||||
case WORK_STATUS:
|
||||
case WORK_COMPLETE, WORK_FAIL, WORK_EXCEPTION:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
return
|
||||
}
|
||||
|
||||
func (client *Client) Echo(data []byte) (err os.Error) {
|
||||
job := NewClientJob(REQ, ECHO_REQ, data)
|
||||
return client.WriteJob(job)
|
||||
func (client *Client) ReadLastJob(datatype uint32) (job *ClientJob, err os.Error){
|
||||
for {
|
||||
if job, err = client.ReadJob(); err != nil {
|
||||
return
|
||||
}
|
||||
if job.dataType == datatype {
|
||||
break
|
||||
}
|
||||
}
|
||||
if job.dataType != datatype {
|
||||
err = os.NewError("No job got.")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (client *Client) Status(handle string) (known, running bool, numerator, denominator uint, err os.Error) {
|
||||
|
||||
if err = client.WriteJob(NewClientJob(REQ, GET_STATUS, []byte(handle))); err != nil {
|
||||
return
|
||||
}
|
||||
var job * ClientJob
|
||||
if job, err = client.ReadLastJob(STATUS_RES); err != nil {
|
||||
return
|
||||
}
|
||||
data := splitByteArray(job.Data, '\x00')
|
||||
if len(data) != 5 {
|
||||
err = os.NewError("Data Error.")
|
||||
return
|
||||
}
|
||||
if handle != string(data[0]) {
|
||||
err = os.NewError("Invalid handle.")
|
||||
return
|
||||
}
|
||||
known = data[1][0] == '1'
|
||||
running = data[2][0] == '1'
|
||||
numerator = uint(data[3][0])
|
||||
denominator = uint(data[4][0])
|
||||
return
|
||||
}
|
||||
|
||||
func (client *Client) Echo(data []byte) (echo []byte, err os.Error) {
|
||||
if err = client.WriteJob(NewClientJob(REQ, ECHO_REQ, data)); err != nil {
|
||||
return
|
||||
}
|
||||
var job *ClientJob
|
||||
if job, err = client.ReadLastJob(ECHO_RES); err != nil {
|
||||
return
|
||||
}
|
||||
return job.Data, err
|
||||
}
|
||||
|
||||
func (client *Client) LastResult() (job *ClientJob) {
|
||||
@ -108,18 +177,6 @@ func (client *Client) LastResult() (job *ClientJob) {
|
||||
return <-client.JobQueue
|
||||
}
|
||||
|
||||
func (client *Client) LastError() (err os.Error) {
|
||||
if l := len(client.ErrQueue); l != 1 {
|
||||
if l == 0 {
|
||||
return
|
||||
}
|
||||
for i := 0; i < l - 1; i ++ {
|
||||
<-client.ErrQueue
|
||||
}
|
||||
}
|
||||
return <-client.ErrQueue
|
||||
}
|
||||
|
||||
func (client *Client) WriteJob(job *ClientJob) (err os.Error) {
|
||||
return client.Write(job.Encode())
|
||||
}
|
||||
@ -136,9 +193,7 @@ func (client *Client) Write(buf []byte) (err os.Error) {
|
||||
}
|
||||
|
||||
func (client *Client) Close() (err os.Error) {
|
||||
client.running = false
|
||||
err = client.conn.Close()
|
||||
close(client.JobQueue)
|
||||
close(client.ErrQueue)
|
||||
return
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package gearman
|
||||
|
||||
import (
|
||||
"os"
|
||||
// "log"
|
||||
)
|
||||
|
||||
type ClientJob struct {
|
||||
@ -47,3 +48,43 @@ func (job *ClientJob) Encode() (data []byte) {
|
||||
return
|
||||
}
|
||||
|
||||
func (job * ClientJob) Result() (data []byte, err os.Error){
|
||||
switch job.dataType {
|
||||
case WORK_FAIL:
|
||||
job.Handle = string(job.Data)
|
||||
err = os.NewError("Work fail.")
|
||||
return
|
||||
case WORK_EXCEPTION:
|
||||
err = os.NewError("Work exception.")
|
||||
fallthrough
|
||||
case WORK_COMPLETE:
|
||||
s := splitByteArray(job.Data, '\x00')
|
||||
if len(s) != 2 {
|
||||
err = os.NewError("Invalid data.")
|
||||
return
|
||||
}
|
||||
job.Handle = string(s[0])
|
||||
data = s[1]
|
||||
default:
|
||||
err = os.NewError("The job is not a result.")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (job *ClientJob) Update() (data []byte, err os.Error) {
|
||||
if job.dataType != WORK_DATA && job.dataType != WORK_WARNING {
|
||||
err = os.NewError("The job is not a update.")
|
||||
return
|
||||
}
|
||||
s := splitByteArray(job.Data, '\x00')
|
||||
if len(s) != 2 {
|
||||
err = os.NewError("Invalid data.")
|
||||
return
|
||||
}
|
||||
if job.dataType == WORK_WARNING {
|
||||
err = os.NewError("Work warning")
|
||||
}
|
||||
job.Handle = string(s[0])
|
||||
data = s[1]
|
||||
return
|
||||
}
|
||||
|
@ -19,17 +19,21 @@ func TestClientAddServer(t * testing.T) {
|
||||
}
|
||||
|
||||
func TestClientEcho(t * testing.T) {
|
||||
if err := client.Echo([]byte("Hello world")); err != nil {
|
||||
if echo, err := client.Echo([]byte("Hello world")); err != nil {
|
||||
t.Error(err)
|
||||
} else {
|
||||
t.Log(echo)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
func TestClientDo(t * testing.T) {
|
||||
if err := client.Do("ToUpper", []byte("abcdef"), JOB_NORMAL); err != nil {
|
||||
if handle, err := client.Do("ToUpper", []byte("abcdef"), JOB_LOW | JOB_BG); err != nil {
|
||||
t.Error(err)
|
||||
} else {
|
||||
t.Log(handle)
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
/*
|
||||
func TestClientLastResult(t * testing.T) {
|
||||
job := client.LastResult()
|
||||
@ -46,3 +50,4 @@ func TestClientClose(t * testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,27 +9,33 @@ const (
|
||||
WORKER_SERVER_CAP = 32
|
||||
WORKER_FUNCTION_CAP = 512
|
||||
QUEUE_CAP = 512
|
||||
BUFFER_SIZE = 1024
|
||||
|
||||
|
||||
// \x00REQ
|
||||
REQ = 5391697
|
||||
REQ_STR = "\x00REQ"
|
||||
// \x00RES
|
||||
RES = 5391699
|
||||
RES_STR = "\x00RES"
|
||||
|
||||
CAN_DO = 1
|
||||
CANT_DO = 2
|
||||
RESET_ABILITIES = 3
|
||||
PRE_SLEEP = 4
|
||||
NOOP = 6
|
||||
JOB_CREATED = 8
|
||||
GRAB_JOB = 9
|
||||
NO_JOB = 10
|
||||
JOB_ASSIGN = 11
|
||||
WORK_STATUS = 12
|
||||
WORK_COMPLETE = 13
|
||||
WORK_FAIL = 14
|
||||
GET_STATUS = 15
|
||||
ECHO_REQ = 16
|
||||
ECHO_RES = 17
|
||||
ERROR = 19
|
||||
STATUS_RES = 20
|
||||
SET_CLIENT_ID = 22
|
||||
CAN_DO_TIMEOUT = 23
|
||||
WORK_EXCEPTION = 25
|
||||
|
@ -121,7 +121,7 @@ func (worker * Worker) Work() {
|
||||
if err := worker.exec(job); err != nil {
|
||||
worker.ErrQueue <- err
|
||||
}
|
||||
continue
|
||||
fallthrough
|
||||
default:
|
||||
worker.JobQueue <- job
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ func (client *jobClient) Work() {
|
||||
}
|
||||
var rel []byte
|
||||
for {
|
||||
buf := make([]byte, 2048)
|
||||
buf := make([]byte, BUFFER_SIZE)
|
||||
n, err := client.conn.Read(buf)
|
||||
if err != nil {
|
||||
if err == os.EOF && n == 0 {
|
||||
@ -40,6 +40,9 @@ func (client *jobClient) Work() {
|
||||
continue OUT
|
||||
}
|
||||
rel = append(rel, buf[0: n] ...)
|
||||
if n < BUFFER_SIZE {
|
||||
break
|
||||
}
|
||||
}
|
||||
job, err := DecodeWorkerJob(rel)
|
||||
if err != nil {
|
||||
|
Loading…
Reference in New Issue
Block a user