urlpoll.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. // Copyright 2010 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package main
  5. import (
  6. "log"
  7. "net/http"
  8. "time"
  9. )
  10. const (
  11. numPollers = 2 // number of Poller goroutines to launch
  12. pollInterval = 60 * time.Second // how often to poll each URL
  13. statusInterval = 10 * time.Second // how often to log status to stdout
  14. errTimeout = 10 * time.Second // back-off timeout on error
  15. )
  16. var urls = []string{
  17. "http://www.google.com/",
  18. "http://golang.org/",
  19. "http://blog.golang.org/",
  20. }
  21. // State represents the last-known state of a URL.
  22. type State struct {
  23. url string
  24. status string
  25. }
  26. // StateMonitor maintains a map that stores the state of the URLs being
  27. // polled, and prints the current state every updateInterval nanoseconds.
  28. // It returns a chan State to which resource state should be sent.
  29. func StateMonitor(updateInterval time.Duration) chan<- State {
  30. updates := make(chan State)
  31. urlStatus := make(map[string]string)
  32. ticker := time.NewTicker(updateInterval)
  33. go func() {
  34. for {
  35. select {
  36. case <-ticker.C:
  37. logState(urlStatus)
  38. case s := <-updates:
  39. urlStatus[s.url] = s.status
  40. }
  41. }
  42. }()
  43. return updates
  44. }
  45. // logState prints a state map.
  46. func logState(s map[string]string) {
  47. log.Println("Current state:")
  48. for k, v := range s {
  49. log.Printf(" %s %s", k, v)
  50. }
  51. }
  52. // Resource represents an HTTP URL to be polled by this program.
  53. type Resource struct {
  54. url string
  55. errCount int
  56. }
  57. // Poll executes an HTTP HEAD request for url
  58. // and returns the HTTP status string or an error string.
  59. func (r *Resource) Poll() string {
  60. resp, err := http.Head(r.url)
  61. if err != nil {
  62. log.Println("Error", r.url, err)
  63. r.errCount++
  64. return err.Error()
  65. }
  66. r.errCount = 0
  67. return resp.Status
  68. }
  69. // Sleep sleeps for an appropriate interval (dependent on error state)
  70. // before sending the Resource to done.
  71. func (r *Resource) Sleep(done chan<- *Resource) {
  72. time.Sleep(pollInterval + errTimeout*time.Duration(r.errCount))
  73. done <- r
  74. }
  75. func Poller(in <-chan *Resource, out chan<- *Resource, status chan<- State) {
  76. for r := range in {
  77. s := r.Poll()
  78. status <- State{r.url, s}
  79. out <- r
  80. }
  81. }
  82. func main() {
  83. // Create our input and output channels.
  84. pending, complete := make(chan *Resource), make(chan *Resource)
  85. // Launch the StateMonitor.
  86. status := StateMonitor(statusInterval)
  87. // Launch some Poller goroutines.
  88. for i := 0; i < numPollers; i++ {
  89. go Poller(pending, complete, status)
  90. }
  91. // Send some Resources to the pending queue.
  92. go func() {
  93. for _, url := range urls {
  94. pending <- &Resource{url: url}
  95. }
  96. }()
  97. for r := range complete {
  98. go r.Sleep(pending)
  99. }
  100. }