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.
 
 
 

161 lines
2.9 KiB

  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. }