

Twitterのフォローを自動化するためのコードをGo言語で書いています。下記のようなコードを書きましたが、途中までは正常に動きフォローもしていきますが、しばらくすると途中で止まってしまいます。コード中の`Exceeded
Rate
Limit.`や`Finished`が出力されていないので意図した箇所で止まってるのではなく異常が起きて止まっている状況です。しかし、どこで処理が止まっているのかがわかりません。あるときは`Add
friends`の後であったり、また、ある時は`Waiting`の後であったりします。

**コード**

[code]

    package autofollow
    
    import (
        "errors"
        "fmt"
        "github.com/ChimeraCoder/anaconda"
        "net/url"
        "os"
        "strconv"
        "time"
    )
    
    var (
        accessToken       string
        accessTokenSecret string
    )
    
    // AutoFollow is object for following.
    type AutoFollow struct {
        words []string
        wn    int
        num   uint
    }
    
    // NewAutoFollow is constructor of AutoFollow.
    func NewAutoFollow(words []string, n uint) (*AutoFollow, error) {
        if consumerKey := os.Getenv("CONSUMER_KEY"); consumerKey == "" {
            return nil, errors.New("CONSUMER_KEY environvariable was not set")
        } else {
            anaconda.SetConsumerKey(consumerKey)
        }
    
        if consumerSecret := os.Getenv("CONSUMER_SECRET"); consumerSecret == "" {
            return nil, errors.New("CONSUMER_SECRET environvariable was not set")
        } else {
            anaconda.SetConsumerSecret(consumerSecret)
        }
    
        if accessToken = os.Getenv("ACCESS_TOKEN"); accessToken == "" {
            return nil, errors.New("ACCESS_TOKEN environvariable was not set")
        }
    
        if accessTokenSecret = os.Getenv("ACCESS_TOKEN_SECRET"); accessTokenSecret == "" {
            return nil, errors.New("ACCESS_TOKEN_SECRET environvariable was not set")
        }
    
        return &AutoFollow{
            words: words,
            wn:    len(words),
            num:   n,
        }, nil
    }
    
    // Follow starts following.
    func (a *AutoFollow) Follow() (chan *anaconda.User, chan bool, chan error, error) {
        c := make(chan *anaconda.User, a.num)
        fnCh := make(chan bool, 1)
        errCh := make(chan error, a.num)
        go a.roop(c, fnCh, errCh)
    
        return c, fnCh, errCh, nil
    }
    
    func (a *AutoFollow) roop(uc chan *anaconda.User, fnCh chan bool, errCh chan error) {
        fCount := 0
        ec := make(chan error, a.wn)
        nc := make(chan bool, a.wn)
        cn := make(chan bool, a.wn)
    
        // それぞれの単語ごとにgoroutineを作る
        for _, v := range a.words {
            fmt.Printf("Starting thread for %s\n", v)
            go a.follow(uc, nc, ec, cn, v)
        }
    
        // 目的の人数に達するまで
    L:
        for {
            // 次に進める
            for i := 0; i < a.wn; i++ {
                nc <- true
            }
            select {
            case err := <-ec:
                if err.(anaconda.TwitterError).Code == anaconda.TwitterErrorRateLimitExceeded {
                    fmt.Println("Exceeded Rate Limit.")
                    // レートリミットに達したら
                    time.Sleep(20 * time.Minute)
                } else {
                    fmt.Printf("error happened %v\n", err)
                    errCh <- err
                }
            case <-cn:
                fmt.Println("Add friends")
                fCount++
                if int(a.num) < fCount {
                    // 目的の人数に達したら終わる
                    fmt.Println("Finished")
                    break L
                }
            default:
            }
        }
        fnCh <- true
    }
    
    func (a *AutoFollow) follow(uc chan *anaconda.User, nc chan bool, ec chan error, cn chan bool, word string) {
        p := 0
        api := anaconda.NewTwitterApi(accessToken, accessTokenSecret)
        for {
            fmt.Println("Waiting")
            <-nc
            v := url.Values{}
            v.Add("page", strconv.Itoa(p))
            v.Add("count", strconv.Itoa(20))
            v.Add("include_entities", "false")
            users, err := api.GetUserSearch(word, v)
            if err != nil {
                // RateLimit
                ec <- err
            } else {
                for _, v := range users {
                    if !v.Following && !v.FollowRequestSent && (v.FollowersCount < v.FriendsCount) {
                        // 友だちになる
                        cn <- true
                        user, err := api.FollowUserId(v.Id, url.Values{})
                        if err != nil {
                            ec <- err
                        } else {
                            uc <- &user
                        }
                    }
                }
            }
            p++
        }
    }
    
[/code]

**出力**

[code]

    Waiting
    Waiting
    Waiting
    Waiting
    Waiting
    Waiting
    Waiting
    Waiting
    Waiting
    Waiting
    Waiting
    Waiting
    Waiting
    Waiting
    Waiting
    Waiting
    Waiting
    Waiting
    Waiting
    Waiting
    Waiting
    Waiting
    Waiting
    Waiting
    Waiting
    Add friends
    Waiting
    Waiting
    Waiting
    Add friends
    Waiting
    Waiting
    Waiting
    Add friends
    Waiting
    Waiting
    Waiting
    Add friends
    Waiting
    
[/code]

なぜ途中で処理がとまってしまうのでしょうか。わかっていることは下記のとおりです。

  * 途中までは正常に動いている

  * 出力がでていなくかつ繰り返し実行してもフォローできているのでレートリミットには達していないと考えられる。

  * 指定したフォローする人数には達していない。

  * エラーも出ていない。


CC BY-SA 3.0
2016-03-03T07:10:00.387
22756
2016-03-03T11:12:04.217
7232
question
go
Goroutineが途中で止まってしまう。


エラーを握りつぶすのをまずやめましょう。


CC BY-SA 3.0
2016-03-03T11:12:04.217
22764
2016-03-03T11:12:04.217
14639
22756
answer