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 2.9 KiB

11 years ago
10 years ago
10 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
10 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
10 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. package worker
  2. import (
  3. "bufio"
  4. "io"
  5. "net"
  6. "strings"
  7. "sync"
  8. )
  9. // The agent of job server.
  10. type agent struct {
  11. sync.Mutex
  12. conn net.Conn
  13. rw *bufio.ReadWriter
  14. worker *Worker
  15. in chan []byte
  16. net, addr string
  17. }
  18. // Create the agent of job server.
  19. func newAgent(net, addr string, worker *Worker) (a *agent, err error) {
  20. a = &agent{
  21. net: net,
  22. addr: addr,
  23. worker: worker,
  24. in: make(chan []byte, queueSize),
  25. }
  26. return
  27. }
  28. func (a *agent) Connect() (err error) {
  29. a.Lock()
  30. defer a.Unlock()
  31. a.conn, err = net.Dial(a.net, a.addr)
  32. if err != nil {
  33. return
  34. }
  35. a.rw = bufio.NewReadWriter(bufio.NewReader(a.conn),
  36. bufio.NewWriter(a.conn))
  37. go a.work()
  38. return
  39. }
  40. func (a *agent) work() {
  41. defer func() {
  42. if err := recover(); err != nil {
  43. a.worker.err(err.(error))
  44. }
  45. }()
  46. var inpack *inPack
  47. var l int
  48. var err error
  49. var data, leftdata []byte
  50. for {
  51. if data, err = a.read(bufferSize); err != nil {
  52. if err == ErrLostConn {
  53. break
  54. }
  55. a.worker.err(err)
  56. // If it is unexpected error and the connection wasn't
  57. // closed by Gearmand, the agent should close the conection
  58. // and reconnect to job server.
  59. a.Close()
  60. a.conn, err = net.Dial(a.net, a.addr)
  61. if err != nil {
  62. a.worker.err(err)
  63. break
  64. }
  65. a.rw = bufio.NewReadWriter(bufio.NewReader(a.conn),
  66. bufio.NewWriter(a.conn))
  67. }
  68. if len(leftdata) > 0 { // some data left for processing
  69. data = append(leftdata, data...)
  70. }
  71. if len(data) < minPacketLength { // not enough data
  72. leftdata = data
  73. continue
  74. }
  75. if inpack, l, err = decodeInPack(data); err != nil {
  76. a.worker.err(err)
  77. leftdata = data
  78. continue
  79. }
  80. leftdata = nil
  81. inpack.a = a
  82. a.worker.in <- inpack
  83. if len(data) > l {
  84. leftdata = data[l:]
  85. }
  86. }
  87. }
  88. func (a *agent) Close() {
  89. a.Lock()
  90. defer a.Unlock()
  91. if a.conn != nil {
  92. a.conn.Close()
  93. a.conn = nil
  94. }
  95. }
  96. func (a *agent) Grab() {
  97. a.Lock()
  98. defer a.Unlock()
  99. outpack := getOutPack()
  100. outpack.dataType = dtGrabJobUniq
  101. a.write(outpack)
  102. }
  103. func (a *agent) PreSleep() {
  104. a.Lock()
  105. defer a.Unlock()
  106. outpack := getOutPack()
  107. outpack.dataType = dtPreSleep
  108. a.write(outpack)
  109. }
  110. func isClosed(err error) bool {
  111. switch {
  112. case err == io.EOF:
  113. fallthrough
  114. case strings.Contains(err.Error(), "use of closed network connection"):
  115. return true
  116. }
  117. return false
  118. }
  119. // read length bytes from the socket
  120. func (a *agent) read(length int) (data []byte, err error) {
  121. n := 0
  122. buf := getBuffer(bufferSize)
  123. // read until data can be unpacked
  124. for i := length; i > 0 || len(data) < minPacketLength; i -= n {
  125. if n, err = a.rw.Read(buf); err != nil {
  126. if isClosed(err) {
  127. err = ErrLostConn
  128. }
  129. return
  130. }
  131. data = append(data, buf[0:n]...)
  132. if n < bufferSize {
  133. break
  134. }
  135. }
  136. return
  137. }
  138. // Internal write the encoded job.
  139. func (a *agent) write(outpack *outPack) (err error) {
  140. var n int
  141. buf := outpack.Encode()
  142. for i := 0; i < len(buf); i += n {
  143. n, err = a.rw.Write(buf[i:])
  144. if err != nil {
  145. return err
  146. }
  147. }
  148. return a.rw.Flush()
  149. }