awesome-patterns/concurrency/subtasks/fetchers/fetchers.go
2018-01-06 16:55:59 +10:00

108 lines
2.3 KiB
Go

package fetchers
import (
"fmt"
"time"
"github.com/davecgh/go-spew/spew"
)
type Fetcher interface {
Fetch(url string) (string, error)
GetName() string
}
type GoogleFetcher struct {
Name string
}
func (g *GoogleFetcher) Fetch(url string) (string, error) {
time.Sleep(time.Second * 1)
return fmt.Sprintf("%s is fetching %s", g.Name, url), nil
}
func (g *GoogleFetcher) GetName() string {
return g.Name
}
func NewGoogleFetcher(name string) *GoogleFetcher {
return &GoogleFetcher{Name: name}
}
type BingFetcher struct {
Name string
}
func (b *BingFetcher) Fetch(url string) (string, error) {
time.Sleep(time.Second * 10)
return fmt.Sprintf("%s is fetching %s", b.Name, url), nil
}
func (b *BingFetcher) GetName() string {
return b.Name
}
func NewBingFetcher(name string) *BingFetcher {
return &BingFetcher{Name: name}
}
type DuckDuckGoFetcher struct {
Name string
}
func (d *DuckDuckGoFetcher) Fetch(url string) (string, error) {
time.Sleep(time.Second * 10)
return fmt.Sprintf("%s is fetching %s", d.Name, url), nil
}
func (d *DuckDuckGoFetcher) GetName() string {
return d.Name
}
func NewDuckDuckGoFetcherFetcher(name string) *DuckDuckGoFetcher {
return &DuckDuckGoFetcher{Name: name}
}
func FetchResults(url string, fetchers []Fetcher, timeout time.Duration) ([]string, []error) {
chStr := make(chan string, len(fetchers))
chErr := make(chan error, len(fetchers))
for _, f := range fetchers {
go func(f Fetcher) {
ch := make(chan string, 1)
eCh := make(chan error, 1)
go func() {
s, err := f.Fetch(url)
if err != nil {
eCh <- err
} else {
ch <- s
}
}()
select {
case r := <-ch:
chStr <- r
case err := <-eCh:
chErr <- err
case <-time.After(timeout):
chErr <- fmt.Errorf("%s timeout after %v on %v", f.GetName(), timeout, url)
}
}(f)
}
stringResults := make([]string, 0, len(fetchers))
errorResults := make([]error, 0, len(fetchers))
for range fetchers {
select {
case s := <-chStr:
stringResults = append(stringResults, s)
case e := <-chErr:
errorResults = append(errorResults, e)
}
}
return stringResults, errorResults
}
func RunFetchers() {
fetchers := []Fetcher{NewGoogleFetcher("Google"), NewBingFetcher("Bing"), NewDuckDuckGoFetcherFetcher("Duck Duck Go")}
r, e := FetchResults("http://www.abc.com", fetchers, time.Second*2)
spew.Dump(r, e)
}