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.
 
 
 

132 lines
3.4 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. gearman "bitbucket.org/mikespook/gearman-go"
  7. "io"
  8. "net"
  9. )
  10. // The agent of job server.
  11. type jobAgent struct {
  12. conn net.Conn
  13. worker *Worker
  14. running bool
  15. incoming chan []byte
  16. }
  17. // Create the agent of job server.
  18. func newJobAgent(addr string, worker *Worker) (jobagent *jobAgent, err error) {
  19. conn, err := net.Dial(gearman.TCP, addr)
  20. if err != nil {
  21. return nil, err
  22. }
  23. jobagent = &jobAgent{conn: conn, worker: worker, running: true, incoming: make(chan []byte, gearman.QUEUE_CAP)}
  24. return jobagent, err
  25. }
  26. // Internal read
  27. func (agent *jobAgent) read() (data []byte, err error) {
  28. if len(agent.incoming) > 0 {
  29. // incoming queue is not empty
  30. data = <-agent.incoming
  31. } else {
  32. for {
  33. buf := make([]byte, gearman.BUFFER_SIZE)
  34. var n int
  35. if n, err = agent.conn.Read(buf); err != nil {
  36. if err == io.EOF && n == 0 {
  37. err = nil
  38. return
  39. }
  40. return
  41. }
  42. data = append(data, buf[0:n]...)
  43. if n < gearman.BUFFER_SIZE {
  44. break
  45. }
  46. }
  47. }
  48. // split package
  49. start := 0
  50. tl := len(data)
  51. for i := 0; i < tl; i++ {
  52. if string(data[start:start+4]) == gearman.RES_STR {
  53. l := int(gearman.BytesToUint32([4]byte{data[start+8], data[start+9], data[start+10], data[start+11]}))
  54. total := l + 12
  55. if total == tl {
  56. return
  57. } else {
  58. agent.incoming <- data[total:]
  59. data = data[:total]
  60. return
  61. }
  62. } else {
  63. start++
  64. }
  65. }
  66. err = gearman.ErrInvalidData
  67. return
  68. }
  69. // Main loop.
  70. func (agent *jobAgent) Work() {
  71. noop := true
  72. for agent.running {
  73. // got noop msg and incoming queue is zero, grab job
  74. if noop && len(agent.incoming) == 0 {
  75. agent.WriteJob(NewWorkerJob(gearman.REQ, gearman.GRAB_JOB, nil))
  76. }
  77. rel, err := agent.read()
  78. if err != nil {
  79. agent.worker.err(err)
  80. continue
  81. }
  82. job, err := DecodeWorkerJob(rel)
  83. if err != nil {
  84. agent.worker.err(err)
  85. continue
  86. } else {
  87. switch job.DataType {
  88. case gearman.NOOP:
  89. noop = true
  90. case gearman.NO_JOB:
  91. noop = false
  92. agent.WriteJob(NewWorkerJob(gearman.REQ, gearman.PRE_SLEEP, nil))
  93. case gearman.ECHO_RES, gearman.JOB_ASSIGN_UNIQ, gearman.JOB_ASSIGN:
  94. job.agent = agent
  95. agent.worker.incoming <- job
  96. }
  97. }
  98. }
  99. return
  100. }
  101. // Send a job to the job server.
  102. func (agent *jobAgent) WriteJob(job *WorkerJob) (err error) {
  103. return agent.write(job.Encode())
  104. }
  105. // Internal write the encoded job.
  106. func (agent *jobAgent) write(buf []byte) (err error) {
  107. var n int
  108. for i := 0; i < len(buf); i += n {
  109. n, err = agent.conn.Write(buf[i:])
  110. if err != nil {
  111. return err
  112. }
  113. }
  114. return
  115. }
  116. // Close.
  117. func (agent *jobAgent) Close() (err error) {
  118. agent.running = false
  119. close(agent.incoming)
  120. err = agent.conn.Close()
  121. return
  122. }