Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 

154 lines
2.7 KiB

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