Browse Source

a better documents

tags/0.2
Xing Xing 10 years ago
parent
commit
18791d0490
9 changed files with 132 additions and 32 deletions
  1. +4
    -1
      .travis.yml
  2. BIN
      example/worker/worker
  3. +26
    -10
      worker/agent.go
  4. +5
    -14
      worker/error.go
  5. +57
    -0
      worker/example_test.go
  6. +7
    -0
      worker/inpack.go
  7. +1
    -0
      worker/job.go
  8. +18
    -7
      worker/worker.go
  9. +14
    -0
      worker/worker_test.go

+ 4
- 1
.travis.yml View File

@@ -1,4 +1,7 @@
language: go
go:
- 1.2

before_install:
- sudo apt-get install -qq gearman-job-server
- sudo apt-get remove -y gearman-job-server
- sudo apt-get install -y gearman-job-server

BIN
example/worker/worker View File


+ 26
- 10
worker/agent.go View File

@@ -3,10 +3,12 @@ package worker
import (
"io"
"net"
"sync"
)

// The agent of job server.
type agent struct {
sync.Mutex
conn net.Conn
worker *Worker
in chan []byte
@@ -25,6 +27,8 @@ func newAgent(net, addr string, worker *Worker) (a *agent, err error) {
}

func (a *agent) Connect() (err error) {
a.Lock()
defer a.Unlock()
a.conn, err = net.Dial(a.net, a.addr)
if err != nil {
return
@@ -40,11 +44,18 @@ func (a *agent) work() {
var data, leftdata []byte
for {
if data, err = a.read(BUFFER_SIZE); err != nil {
if err == ErrConnClosed {
a.worker.err(err)
if err == ErrLostConn {
break
}
// If it is unexpected error and the connection wasn't
// closed by Gearmand, the agent should colse the conection
// and reconnect to job server.
a.conn, err = net.Dial(a.net, a.addr)
if err != nil {
a.worker.err(err)
break
}
a.worker.err(err)
continue
}
if len(leftdata) > 0 { // some data left for processing
data = append(leftdata, data...)
@@ -67,16 +78,25 @@ func (a *agent) work() {
}

func (a *agent) Close() {
a.conn.Close()
a.Lock()
defer a.Unlock()
if a.conn != nil {
a.conn.Close()
a.conn = nil
}
}

func (a *agent) Grab() {
a.Lock()
defer a.Unlock()
outpack := getOutPack()
outpack.dataType = GRAB_JOB_UNIQ
a.write(outpack)
}

func (a *agent) PreSleep() {
a.Lock()
defer a.Unlock()
outpack := getOutPack()
outpack.dataType = PRE_SLEEP
a.write(outpack)
@@ -89,12 +109,8 @@ func (a *agent) read(length int) (data []byte, err error) {
// read until data can be unpacked
for i := length; i > 0 || len(data) < MIN_PACKET_LEN; i -= n {
if n, err = a.conn.Read(buf); err != nil {
if err == io.EOF && n == 0 {
if data == nil {
err = ErrConnection
} else {
err = ErrConnClosed
}
if err == io.EOF {
err = ErrLostConn
}
return
}


+ 5
- 14
worker/error.go View File

@@ -7,20 +7,11 @@ import (
)

var (
ErrJobTimeOut = errors.New("Do a job time out")
ErrInvalidData = errors.New("Invalid data")
ErrWorkWarning = errors.New("Work warning")
ErrWorkFail = errors.New("Work fail")
ErrWorkException = errors.New("Work exeption")
ErrDataType = errors.New("Invalid data type")
ErrOutOfCap = errors.New("Out of the capability")
ErrNotConn = errors.New("Did not connect to job server")
ErrFuncNotFound = errors.New("The function was not found")
ErrConnection = errors.New("Connection error")
ErrNoActiveAgent = errors.New("No active agent")
ErrTimeOut = errors.New("Executing time out")
ErrUnknown = errors.New("Unknown error")
ErrConnClosed = errors.New("Connection closed")
ErrNoneAgents = errors.New("None active agents")
ErrNoneFuncs = errors.New("None functions")
ErrTimeOut = errors.New("Executing time out")
ErrUnknown = errors.New("Unknown error")
ErrLostConn = errors.New("Lost connection with Gearmand")
)

// Extract the error message


+ 57
- 0
worker/example_test.go View File

@@ -0,0 +1,57 @@
package worker_test

import (
"fmt"
"github.com/mikespook/gearman-go/worker"
"sync"
)

func ExampleWorker() {
// An example of worker
w := worker.New(worker.Unlimited)
defer w.Close()
// Add a gearman job server
if err := w.AddServer("tcp4", "127.0.0.1:4730"); err != nil {
fmt.Println(err)
return
}
// A function for handling jobs
foobar := func(job worker.Job) ([]byte, error) {
// Do nothing here
return nil, nil
}
// Add the function to worker
if err := w.AddFunc("foobar", foobar, 0); err != nil {
fmt.Println(err)
return
}
var wg sync.WaitGroup
// A custome handler, for handling other results, eg. ECHO, ERROR.
w.JobHandler = func(job worker.Job) error {
if job.Err() == nil {
fmt.Println(string(job.Data()))
} else {
fmt.Println(job.Err())
}
wg.Done()
return nil
}
// An error handler for handling worker's internal errors.
w.ErrorHandler = func(e error) {
fmt.Println(e)
// Ignore the error or shutdown the worker
}
// Tell Gearman job server: I'm ready!
if err := w.Ready(); err != nil {
fmt.Println(err)
return
}
// Running main loop
go w.Work()
wg.Add(1)
// calling Echo
w.Echo([]byte("Hello"))
// Waiting results
wg.Wait()
// Output: Hello
}

+ 7
- 0
worker/inpack.go View File

@@ -24,6 +24,13 @@ func (inpack *inPack) Data() []byte {
return inpack.data
}

func (inpack *inPack) Err() error {
if inpack.dataType == ERROR {
return GetError(inpack.data)
}
return nil
}

// Send some datas to client.
// Using this in a job's executing.
func (inpack *inPack) SendData(data []byte) {


+ 1
- 0
worker/job.go View File

@@ -1,6 +1,7 @@
package worker

type Job interface {
Err() error
Data() []byte
SendWarning(data []byte)
SendData(data []byte)


+ 18
- 7
worker/worker.go View File

@@ -10,10 +10,10 @@ import (
)

const (
Unlimited = 0
OneByOne = 1
Unlimited = iota
OneByOne

Immediately = 0
Immediately = iota
)

// Worker is the only structure needed by worker side developing.
@@ -139,8 +139,6 @@ func (worker *Worker) handleInPack(inpack *inPack) {
inpack.a.PreSleep()
case NOOP:
inpack.a.Grab()
case ERROR:
worker.err(GetError(inpack.data))
case JOB_ASSIGN, JOB_ASSIGN_UNIQ:
go func() {
if err := worker.exec(inpack); err != nil {
@@ -151,6 +149,9 @@ func (worker *Worker) handleInPack(inpack *inPack) {
worker.limit <- true
}
inpack.a.Grab()
case ERROR:
worker.err(inpack.Err())
fallthrough
case ECHO_RES:
fallthrough
default:
@@ -161,6 +162,12 @@ func (worker *Worker) handleInPack(inpack *inPack) {
// Connect to Gearman server and tell every server
// what can this worker do.
func (worker *Worker) Ready() (err error) {
if len(worker.agents) == 0 {
return ErrNoneAgents
}
if len(worker.funcs) == 0 {
return ErrNoneFuncs
}
for _, v := range worker.agents {
if err = v.Connect(); err != nil {
return
@@ -201,8 +208,12 @@ func (worker *Worker) customeHandler(inpack *inPack) {

// Close connection and exit main loop
func (worker *Worker) Close() {
worker.running = false
close(worker.in)
worker.Lock()
worker.Unlock()
if worker.running == true {
worker.running = false
close(worker.in)
}
}

// Echo


+ 14
- 0
worker/worker_test.go View File

@@ -11,6 +11,13 @@ func init() {
worker = New(Unlimited)
}

func TestWorkerErrNoneAgents(t *testing.T) {
err := worker.Ready()
if err != ErrNoneAgents {
t.Error("ErrNoneAgents expected.")
}
}

func TestWorkerAddServer(t *testing.T) {
t.Log("Add local server 127.0.0.1:4730.")
if err := worker.AddServer("tcp4", "127.0.0.1:4730"); err != nil {
@@ -23,6 +30,13 @@ func TestWorkerAddServer(t *testing.T) {
}
}

func TestWorkerErrNoneFuncs(t *testing.T) {
err := worker.Ready()
if err != ErrNoneFuncs {
t.Error("ErrNoneFuncs expected.")
}
}

func foobar(job Job) ([]byte, error) {
return nil, nil
}


Loading…
Cancel
Save