You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

162 lines
3.8 KiB

  1. // Copyright 2011 Xing Xing <mikespook@gmail.com> All rights reserved.
  2. // Use of this source code is governed by a MIT
  3. // license that can be found in the LICENSE file.
  4. package worker
  5. import (
  6. "io"
  7. "net"
  8. "bitbucket.org/mikespook/gearman-go/common"
  9. )
  10. // The agent of job server.
  11. type agent struct {
  12. conn net.Conn
  13. worker *Worker
  14. in chan []byte
  15. out chan *Job
  16. }
  17. // Create the agent of job server.
  18. func newAgent(addr string, worker *Worker) (a *agent, err error) {
  19. conn, err := net.Dial(common.NETWORK, addr)
  20. if err != nil {
  21. return
  22. }
  23. a = &agent{
  24. conn: conn,
  25. worker: worker,
  26. in: make(chan []byte, common.QUEUE_SIZE),
  27. out: make(chan *Job, common.QUEUE_SIZE),
  28. }
  29. return
  30. }
  31. // outputing loop
  32. func (a *agent) outLoop() {
  33. ok := true
  34. var job *Job
  35. for ok {
  36. if job, ok = <-a.out; ok {
  37. if err := a.write(job.Encode()); err != nil {
  38. a.worker.err(err)
  39. }
  40. }
  41. }
  42. }
  43. // inputing loop
  44. func (a *agent) inLoop() {
  45. defer func() {
  46. recover()
  47. close(a.in)
  48. close(a.out)
  49. a.worker.removeAgent(a)
  50. }()
  51. noop := true
  52. for a.worker.running {
  53. // got noop msg and in queue is zero, grab job
  54. if noop && len(a.in) == 0 {
  55. a.WriteJob(newJob(common.REQ, common.GRAB_JOB, nil))
  56. }
  57. rel, err := a.read()
  58. if err != nil {
  59. if err == common.ErrConnection {
  60. // TODO: reconnection
  61. break
  62. }
  63. a.worker.err(err)
  64. continue
  65. }
  66. job, err := decodeJob(rel)
  67. if err != nil {
  68. a.worker.err(err)
  69. continue
  70. }
  71. switch job.DataType {
  72. case common.NOOP:
  73. noop = true
  74. case common.NO_JOB:
  75. noop = false
  76. a.WriteJob(newJob(common.REQ, common.PRE_SLEEP, nil))
  77. case common.ERROR, common.ECHO_RES, common.JOB_ASSIGN_UNIQ, common.JOB_ASSIGN:
  78. job.agent = a
  79. a.worker.in <- job
  80. }
  81. }
  82. }
  83. func (a *agent) Close() {
  84. a.conn.Close()
  85. }
  86. func (a *agent) Work() {
  87. go a.outLoop()
  88. go a.inLoop()
  89. }
  90. // Internal read
  91. func (a *agent) read() (data []byte, err error) {
  92. if len(a.in) > 0 {
  93. // in queue is not empty
  94. data = <-a.in
  95. } else {
  96. for {
  97. buf := make([]byte, common.BUFFER_SIZE)
  98. var n int
  99. if n, err = a.conn.Read(buf); err != nil {
  100. if err == io.EOF && n == 0 {
  101. if data == nil {
  102. err = common.ErrConnection
  103. return
  104. }
  105. break
  106. }
  107. return
  108. }
  109. data = append(data, buf[0:n]...)
  110. if n < common.BUFFER_SIZE {
  111. break
  112. }
  113. }
  114. }
  115. // split package
  116. tl := len(data)
  117. start := 0
  118. for i := 0; i < tl; i++ {
  119. if string(data[start:start+4]) == common.RES_STR {
  120. l := int(common.BytesToUint32([4]byte{data[start+8],
  121. data[start+9], data[start+10], data[start+11]}))
  122. total := l + 12
  123. if total == tl {
  124. return
  125. } else {
  126. a.in <- data[total:]
  127. data = data[:total]
  128. return
  129. }
  130. } else {
  131. start++
  132. }
  133. }
  134. return nil, common.Errorf("Invalid data: %V", data)
  135. }
  136. // Send a job to the job server.
  137. func (a *agent) WriteJob(job *Job) {
  138. a.out <- job
  139. }
  140. // Internal write the encoded job.
  141. func (a *agent) write(buf []byte) (err error) {
  142. var n int
  143. for i := 0; i < len(buf); i += n {
  144. n, err = a.conn.Write(buf[i:])
  145. if err != nil {
  146. return err
  147. }
  148. }
  149. return
  150. }