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.

agent.go 4.8 KiB

11 jaren geleden
12 jaren geleden
11 jaren geleden
11 jaren geleden
11 jaren geleden
11 jaren geleden
11 jaren geleden
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  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. "github.com/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. // reset abilities
  32. a.WriteJob(newJob(common.REQ, common.RESET_ABILITIES, nil))
  33. return
  34. }
  35. // outputing loop
  36. func (a *agent) outLoop() {
  37. ok := true
  38. var job *Job
  39. for ok {
  40. if job, ok = <-a.out; ok {
  41. if err := a.write(job.Encode()); err != nil {
  42. a.worker.err(err)
  43. }
  44. }
  45. }
  46. }
  47. // inputing loop
  48. func (a *agent) inLoop() {
  49. defer func() {
  50. if r := recover(); r != nil {
  51. a.worker.err(common.Errorf("Exiting: %s", r))
  52. }
  53. close(a.in)
  54. close(a.out)
  55. a.worker.removeAgent(a)
  56. }()
  57. for a.worker.running {
  58. a.WriteJob(newJob(common.REQ, common.PRE_SLEEP, nil))
  59. RESTART:
  60. // got noop msg and in queue is zero, grab job
  61. rel, err := a.read()
  62. if err != nil {
  63. if err == common.ErrConnection {
  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. a.WriteJob(newJob(common.REQ, common.GRAB_JOB_UNIQ, nil))
  87. case common.ERROR, common.ECHO_RES, common.JOB_ASSIGN_UNIQ, common.JOB_ASSIGN:
  88. job.agent = a
  89. a.worker.in <- job
  90. }
  91. }
  92. }
  93. func (a *agent) Close() {
  94. a.conn.Close()
  95. }
  96. func (a *agent) Work() {
  97. go a.outLoop()
  98. go a.inLoop()
  99. }
  100. // Internal read
  101. func (a *agent) read() (data []byte, err error) {
  102. BEGIN:
  103. inlen := len(a.in)
  104. if inlen > 0 {
  105. // in queue is not empty
  106. for i := 0; i < inlen; i ++ {
  107. data = append(data, <-a.in...)
  108. }
  109. } else {
  110. for i := 0; i < 10; i ++ {
  111. buf := make([]byte, common.BUFFER_SIZE)
  112. var n int
  113. if n, err = a.conn.Read(buf); err != nil {
  114. if err == io.EOF && n == 0 {
  115. if data == nil {
  116. err = common.ErrConnection
  117. return
  118. }
  119. break
  120. }
  121. return
  122. }
  123. data = append(data, buf[0:n]...)
  124. if n < common.BUFFER_SIZE {
  125. break
  126. }
  127. }
  128. }
  129. // split package
  130. tl := len(data)
  131. if tl < 12 { // too few data to unpack, read more
  132. goto BEGIN
  133. }
  134. start := 0
  135. for i := 0; i < tl - 11; i++ {
  136. if start + 12 > tl { // too few data to unpack, read more
  137. goto BEGIN
  138. }
  139. if string(data[start:start+4]) == common.RES_STR {
  140. l := int(common.BytesToUint32([4]byte{data[start+8],
  141. data[start+9], data[start+10], data[start+11]}))
  142. total := l + 12
  143. if total == tl { // data is what we want
  144. return
  145. } else if total < tl{ // data[:total] is what we want, data[total:] is the more
  146. a.in <- data[total:]
  147. data = data[:total]
  148. return
  149. } else { // ops! It won't be possible.
  150. goto BEGIN
  151. }
  152. } else { // flag was not found, move to next step
  153. start++
  154. }
  155. }
  156. goto BEGIN
  157. return nil, common.Errorf("Invalid data: %V", data)
  158. }
  159. // Send a job to the job server.
  160. func (a *agent) WriteJob(job *Job) {
  161. a.out <- job
  162. }
  163. // Internal write the encoded job.
  164. func (a *agent) write(buf []byte) (err error) {
  165. var n int
  166. for i := 0; i < len(buf); i += n {
  167. n, err = a.conn.Write(buf[i:])
  168. if err != nil {
  169. return err
  170. }
  171. }
  172. return
  173. }