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.
 
 
 

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