2019-01-04 06:46:13 +00:00
|
|
|
package consumer
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"fmt"
|
|
|
|
|
"sync"
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
"github.com/aws/aws-sdk-go/aws"
|
|
|
|
|
"github.com/aws/aws-sdk-go/service/kinesis"
|
|
|
|
|
"github.com/aws/aws-sdk-go/service/kinesis/kinesisiface"
|
|
|
|
|
)
|
|
|
|
|
|
2019-04-09 03:33:39 +00:00
|
|
|
const pollFreq = 30 * time.Second
|
|
|
|
|
|
|
|
|
|
func newBroker(client kinesisiface.KinesisAPI, streamName string, shardc chan *kinesis.Shard) *broker {
|
2019-01-04 06:46:13 +00:00
|
|
|
return &broker{
|
|
|
|
|
client: client,
|
|
|
|
|
shards: make(map[string]*kinesis.Shard),
|
|
|
|
|
streamName: streamName,
|
|
|
|
|
shardc: shardc,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-09 03:41:41 +00:00
|
|
|
// broker caches a local list of the shards we are already processing
|
2019-04-09 03:33:39 +00:00
|
|
|
// and routinely polls the stream looking for new shards to process
|
2019-01-04 06:46:13 +00:00
|
|
|
type broker struct {
|
|
|
|
|
client kinesisiface.KinesisAPI
|
|
|
|
|
streamName string
|
|
|
|
|
shardc chan *kinesis.Shard
|
|
|
|
|
|
|
|
|
|
shardMu sync.Mutex
|
|
|
|
|
shards map[string]*kinesis.Shard
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-09 03:41:41 +00:00
|
|
|
// pollShards loops forever attempting to find new shards
|
|
|
|
|
// to process
|
2019-04-08 18:16:09 +00:00
|
|
|
func (b *broker) pollShards(ctx context.Context) {
|
2019-04-09 03:41:41 +00:00
|
|
|
b.leaseShards()
|
|
|
|
|
|
|
|
|
|
for {
|
|
|
|
|
select {
|
|
|
|
|
case <-ctx.Done():
|
|
|
|
|
return
|
|
|
|
|
case <-time.After(pollFreq):
|
|
|
|
|
b.leaseShards()
|
2019-01-04 06:46:13 +00:00
|
|
|
}
|
2019-04-09 03:41:41 +00:00
|
|
|
}
|
2019-01-04 06:46:13 +00:00
|
|
|
}
|
|
|
|
|
|
2019-04-09 03:41:41 +00:00
|
|
|
// leaseShards attempts to find new shards that need to be
|
|
|
|
|
// processed; when a new shard is found it passing the shard
|
|
|
|
|
// ID back to the consumer on the shard channel
|
|
|
|
|
func (b *broker) leaseShards() {
|
|
|
|
|
b.shardMu.Lock()
|
|
|
|
|
defer b.shardMu.Unlock()
|
|
|
|
|
|
2019-01-04 06:46:13 +00:00
|
|
|
shards, err := b.listShards()
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Println(err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, shard := range shards {
|
2019-04-09 03:41:41 +00:00
|
|
|
if _, ok := b.shards[*shard.ShardId]; ok {
|
|
|
|
|
continue
|
2019-01-04 06:46:13 +00:00
|
|
|
}
|
2019-04-09 03:41:41 +00:00
|
|
|
|
|
|
|
|
b.shards[*shard.ShardId] = shard
|
|
|
|
|
b.shardc <- shard
|
2019-01-04 06:46:13 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-09 03:41:41 +00:00
|
|
|
// listShards pulls a list of shard IDs from the kinesis api
|
2019-01-04 06:46:13 +00:00
|
|
|
func (b *broker) listShards() ([]*kinesis.Shard, error) {
|
|
|
|
|
var ss []*kinesis.Shard
|
|
|
|
|
var listShardsInput = &kinesis.ListShardsInput{
|
|
|
|
|
StreamName: aws.String(b.streamName),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for {
|
|
|
|
|
resp, err := b.client.ListShards(listShardsInput)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("ListShards error: %v", err)
|
|
|
|
|
}
|
|
|
|
|
ss = append(ss, resp.Shards...)
|
|
|
|
|
|
|
|
|
|
if resp.NextToken == nil {
|
|
|
|
|
return ss, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
listShardsInput = &kinesis.ListShardsInput{
|
|
|
|
|
NextToken: resp.NextToken,
|
|
|
|
|
StreamName: aws.String(b.streamName),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|