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.

asynchttp.go 1.8KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. package net
  2. import (
  3. "net/http"
  4. "sync/atomic"
  5. "time"
  6. )
  7. // Max number of HTTP workers
  8. var MaxWorkers uint32 = 4
  9. // Current number of HTTP workers
  10. // atomic variable, don't use directly
  11. var activeWorkers int32
  12. // Kill a worker routine if it
  13. // doesn't get any jobs after "timeOut"
  14. const timeOut = 10 * time.Second
  15. // Result of the HTTP request
  16. type JobResult struct {
  17. // HTTP Response (can be nil)
  18. Res *http.Response
  19. // HTTP error (can be nil)
  20. Err error
  21. // data parameter from DoAsyncHTTP
  22. ReqData interface{} // job.data
  23. }
  24. type job struct {
  25. req *http.Request
  26. c chan JobResult
  27. data interface{}
  28. }
  29. // Job queue
  30. var jobs = make(chan job)
  31. // Enqueue a new HTTP request and send the result to "c" (send to "c" guaranteed)
  32. // Additional data like an ID can be passed in "data" to be returned with "c"
  33. func DoAsyncHTTP(r *http.Request, c chan JobResult, data interface{}) {
  34. newJob := job{r, c, data}
  35. select {
  36. // Try to send to the channel and
  37. // see if an idle worker picks the job up
  38. case jobs <- newJob:
  39. break
  40. // Every routine is busy
  41. default:
  42. if atomic.LoadInt32(&activeWorkers) < int32(MaxWorkers) {
  43. // Another thread is allowed to spawn
  44. // TODO Race condition here: DoAsyncHTTP is not thread safe!
  45. atomic.AddInt32(&activeWorkers, 1)
  46. go asyncHTTPWorker()
  47. }
  48. // Block until another routine finishes
  49. jobs <- newJob
  50. }
  51. }
  52. // Routine that reads continually reads requests from "jobs"
  53. // and quits if it doesn't find any jobs for some time
  54. func asyncHTTPWorker() {
  55. for {
  56. select {
  57. // Get a new job from the queue and process it
  58. case job := <-jobs:
  59. res, err := Client.Do(job.req)
  60. job.c <- JobResult{res, err, job.data}
  61. // Timeout, kill the routine
  62. case <-time.After(timeOut):
  63. atomic.AddInt32(&activeWorkers, -1)
  64. return
  65. }
  66. }
  67. }