diff --git a/.gitignore b/.gitignore index 6b6813b..47a8300 100644 --- a/.gitignore +++ b/.gitignore @@ -38,7 +38,7 @@ tags* # Vendored files vendor/** -!vendor/manifest +!vendor/vendor.json # Benchmark files prof.cpu diff --git a/README.md b/README.md index 42c3578..8b82f9e 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,14 @@ func main() { } ``` +### Config + +The default behavior for checkpointing uses Redis on localhost. To set a custom Redis URL use ENV vars: + +``` +REDIS_URL=my-custom-redis-server.com:6379 +``` + ### Logging [Apex Log](https://medium.com/@tjholowaychuk/apex-log-e8d9627f4a9a#.5x1uo1767) is used for logging Info. Override the logs format with other [Log Handlers](https://github.com/apex/log/tree/master/_examples). For example using the "json" log handler: @@ -70,14 +78,14 @@ Get the package source: ### Fetching Dependencies -Install `gvt`: +Install `govendor`: $ export GO15VENDOREXPERIMENT=1 - $ go get github.com/FiloSottile/gvt + $ go get -u github.com/kardianos/govendor Install dependencies into `./vendor/`: - $ gvt restore + $ govendor sync ### Examples @@ -86,7 +94,6 @@ Use the [seed stream](https://github.com/harlow/kinesis-connectors/tree/master/e * [Firehose](https://github.com/harlow/kinesis-connectors/tree/master/examples/firehose) * [S3](https://github.com/harlow/kinesis-connectors/tree/master/examples/s3) - ## Contributing Please see [CONTRIBUTING.md] for more information. Thank you, [contributors]! diff --git a/checkpoint.go b/checkpoint.go index 0ff948d..001d337 100644 --- a/checkpoint.go +++ b/checkpoint.go @@ -1,48 +1,9 @@ package connector -import ( - "fmt" - - "github.com/hoisie/redis" -) - -// RedisCheckpoint implements the Checkpont interface. -// This class is used to enable the Pipeline.ProcessShard to checkpoint their progress. -type Checkpoint struct { - AppName string - StreamName string - - client redis.Client - sequenceNumber string -} - -// CheckpointExists determines if a checkpoint for a particular Shard exists. -// Typically used to determine whether we should start processing the shard with -// TRIM_HORIZON or AFTER_SEQUENCE_NUMBER (if checkpoint exists). -func (c *Checkpoint) CheckpointExists(shardID string) bool { - val, _ := c.client.Get(c.key(shardID)) - - if val != nil && string(val) != "" { - c.sequenceNumber = string(val) - return true - } - - return false -} - -// SequenceNumber returns the current checkpoint stored for the specified shard. -func (c *Checkpoint) SequenceNumber() string { - return c.sequenceNumber -} - -// SetCheckpoint stores a checkpoint for a shard (e.g. sequence number of last record processed by application). -// Upon failover, record processing is resumed from this point. -func (c *Checkpoint) SetCheckpoint(shardID string, sequenceNumber string) { - c.client.Set(c.key(shardID), []byte(sequenceNumber)) - c.sequenceNumber = sequenceNumber -} - -// key generates a unique Redis key for storage of Checkpoint. -func (c *Checkpoint) key(shardID string) string { - return fmt.Sprintf("%v:checkpoint:%v:%v", c.AppName, c.StreamName, shardID) +// Checkpoint interface for functions that checkpoints need to +// implement in order to track consumer progress. +type Checkpoint interface { + CheckpointExists(shardID string) bool + SequenceNumber() string + SetCheckpoint(shardID string, sequenceNumber string) } diff --git a/checkpoint_test.go b/checkpoint_test.go deleted file mode 100644 index d06d7ee..0000000 --- a/checkpoint_test.go +++ /dev/null @@ -1,46 +0,0 @@ -package connector - -import ( - "testing" - - "github.com/bmizerany/assert" - "github.com/hoisie/redis" -) - -func Test_key(t *testing.T) { - c := Checkpoint{ - AppName: "app", - StreamName: "stream", - } - - k := c.key("shard") - assert.Equal(t, k, "app:checkpoint:stream:shard") -} - -func Test_CheckpointExists(t *testing.T) { - var rc redis.Client - rc.Set("app:checkpoint:stream:shard", []byte("testSeqNum")) - c := Checkpoint{ - AppName: "app", - StreamName: "stream", - } - - r := c.CheckpointExists("shard") - assert.Equal(t, r, true) - - rc.Del("app:checkpoint:stream:shard") -} - -func Test_SetCheckpoint(t *testing.T) { - var rc redis.Client - c := Checkpoint{ - AppName: "app", - StreamName: "stream", - } - - c.SetCheckpoint("shard", "testSeqNum") - r, _ := rc.Get("app:checkpoint:stream:shard") - assert.Equal(t, string(r), "testSeqNum") - - rc.Del("app:checkpoint:stream:shard") -} diff --git a/config.go b/config.go index 90cd3f4..a110cde 100644 --- a/config.go +++ b/config.go @@ -4,15 +4,19 @@ import ( "os" "time" + redis "gopkg.in/redis.v5" + "github.com/apex/log" ) const ( defaultBufferSize = 500 + defaultRedisAddr = "127.0.0.1:6379" ) +// Config vars for the application type Config struct { - // AppName is the application name. + // AppName is the application name and checkpoint namespace. AppName string // StreamName is the Kinesis stream. @@ -26,6 +30,9 @@ type Config struct { // Logger is the logger used. Defaults to log.Log. Logger log.Interface + + // Checkpoint for tracking progress of consumer. + Checkpoint Checkpoint } // defaults for configuration. @@ -60,4 +67,32 @@ func (c *Config) setDefaults() { if c.FlushInterval == 0 { c.FlushInterval = time.Second } + + if c.Checkpoint == nil { + client, err := redisClient() + if err != nil { + c.Logger.WithError(err).Error("Redis connection failed") + os.Exit(1) + } + c.Checkpoint = &RedisCheckpoint{ + AppName: c.AppName, + StreamName: c.StreamName, + client: client, + } + } +} + +func redisClient() (*redis.Client, error) { + redisURL := os.Getenv("REDIS_URL") + if redisURL == "" { + redisURL = defaultRedisAddr + } + client := redis.NewClient(&redis.Options{ + Addr: redisURL, + }) + _, err := client.Ping().Result() + if err != nil { + return nil, err + } + return client, nil } diff --git a/consumer.go b/consumer.go index ce70360..ec6a9b5 100644 --- a/consumer.go +++ b/consumer.go @@ -54,19 +54,14 @@ func (c *Consumer) handlerLoop(shardID string, handler Handler) { MaxRecordCount: c.BufferSize, } - checkpoint := &Checkpoint{ - AppName: c.AppName, - StreamName: c.StreamName, - } - params := &kinesis.GetShardIteratorInput{ ShardId: aws.String(shardID), StreamName: aws.String(c.StreamName), } - if checkpoint.CheckpointExists(shardID) { + if c.Checkpoint.CheckpointExists(shardID) { params.ShardIteratorType = aws.String("AFTER_SEQUENCE_NUMBER") - params.StartingSequenceNumber = aws.String(checkpoint.SequenceNumber()) + params.StartingSequenceNumber = aws.String(c.Checkpoint.SequenceNumber()) } else { params.ShardIteratorType = aws.String("TRIM_HORIZON") } @@ -103,7 +98,7 @@ func (c *Consumer) handlerLoop(shardID string, handler Handler) { if buf.ShouldFlush() { handler.HandleRecords(*buf) ctx.WithField("count", buf.RecordCount()).Info("flushed") - checkpoint.SetCheckpoint(shardID, buf.LastSeq()) + c.Checkpoint.SetCheckpoint(shardID, buf.LastSeq()) buf.Flush() } } diff --git a/redis_checkpoint.go b/redis_checkpoint.go new file mode 100644 index 0000000..7195cc7 --- /dev/null +++ b/redis_checkpoint.go @@ -0,0 +1,53 @@ +package connector + +import ( + "fmt" + "log" + + "gopkg.in/redis.v5" +) + +// RedisCheckpoint implements the Checkpont interface. +// Used to enable the Pipeline.ProcessShard to checkpoint it's progress +// while reading records from Kinesis stream. +type RedisCheckpoint struct { + AppName string + StreamName string + + client *redis.Client + sequenceNumber string +} + +// CheckpointExists determines if a checkpoint for a particular Shard exists. +// Typically used to determine whether we should start processing the shard with +// TRIM_HORIZON or AFTER_SEQUENCE_NUMBER (if checkpoint exists). +func (c *RedisCheckpoint) CheckpointExists(shardID string) bool { + val, _ := c.client.Get(c.key(shardID)).Result() + + if val != "" { + c.sequenceNumber = val + return true + } + + return false +} + +// SequenceNumber returns the current checkpoint stored for the specified shard. +func (c *RedisCheckpoint) SequenceNumber() string { + return c.sequenceNumber +} + +// SetCheckpoint stores a checkpoint for a shard (e.g. sequence number of last record processed by application). +// Upon failover, record processing is resumed from this point. +func (c *RedisCheckpoint) SetCheckpoint(shardID string, sequenceNumber string) { + err := c.client.Set(c.key(shardID), sequenceNumber, 0).Err() + if err != nil { + log.Printf("redis checkpoint set error: %v", err) + } + c.sequenceNumber = sequenceNumber +} + +// key generates a unique Redis key for storage of Checkpoint. +func (c *RedisCheckpoint) key(shardID string) string { + return fmt.Sprintf("%v:checkpoint:%v:%v", c.AppName, c.StreamName, shardID) +} diff --git a/redis_checkpoint_test.go b/redis_checkpoint_test.go new file mode 100644 index 0000000..b0e1360 --- /dev/null +++ b/redis_checkpoint_test.go @@ -0,0 +1,50 @@ +package connector + +import ( + "testing" + + "gopkg.in/redis.v5" +) + +var defaultAddr = "127.0.0.1:6379" + +func Test_CheckpointLifecycle(t *testing.T) { + client := redis.NewClient(&redis.Options{Addr: defaultAddr}) + + c := RedisCheckpoint{ + AppName: "app", + StreamName: "stream", + client: client, + } + + // set checkpoint + c.SetCheckpoint("shard_id", "testSeqNum") + + // checkpoint exists + if val := c.CheckpointExists("shard_id"); val != true { + t.Fatalf("checkpoint exists expected true, got %t", val) + } + + // get checkpoint + if val := c.SequenceNumber(); val != "testSeqNum" { + t.Fatalf("checkpoint exists expected %s, got %s", "testSeqNum", val) + } + + client.Del("app:checkpoint:stream:shard_id") +} + +func Test_key(t *testing.T) { + client := redis.NewClient(&redis.Options{Addr: defaultAddr}) + + c := &RedisCheckpoint{ + AppName: "app", + StreamName: "stream", + client: client, + } + + expected := "app:checkpoint:stream:shard" + + if val := c.key("shard"); val != expected { + t.Fatalf("checkpoint exists expected %s, got %s", expected, val) + } +} diff --git a/vendor/manifest b/vendor/manifest deleted file mode 100644 index f2aa44a..0000000 --- a/vendor/manifest +++ /dev/null @@ -1,166 +0,0 @@ -{ - "version": 0, - "dependencies": [ - { - "importpath": "github.com/apex/log", - "repository": "https://github.com/apex/log", - "vcs": "git", - "revision": "c20bfcdb771b706fdd57a954ee9da2d0ff97b02d", - "branch": "master", - "notests": true - }, - { - "importpath": "github.com/apex/log/handlers/discard", - "repository": "https://github.com/apex/log", - "vcs": "git", - "revision": "c20bfcdb771b706fdd57a954ee9da2d0ff97b02d", - "branch": "master", - "path": "/handlers/discard", - "notests": true - }, - { - "importpath": "github.com/aws/aws-sdk-go/aws", - "repository": "https://github.com/aws/aws-sdk-go", - "vcs": "git", - "revision": "966f1a968ba8e260628dfa6be07bcd48d8e98ef6", - "branch": "master", - "path": "/aws", - "notests": true - }, - { - "importpath": "github.com/aws/aws-sdk-go/aws/session", - "repository": "https://github.com/aws/aws-sdk-go", - "vcs": "git", - "revision": "966f1a968ba8e260628dfa6be07bcd48d8e98ef6", - "branch": "master", - "path": "/aws/session", - "notests": true - }, - { - "importpath": "github.com/aws/aws-sdk-go/private/endpoints", - "repository": "https://github.com/aws/aws-sdk-go", - "vcs": "git", - "revision": "966f1a968ba8e260628dfa6be07bcd48d8e98ef6", - "branch": "master", - "path": "/private/endpoints", - "notests": true - }, - { - "importpath": "github.com/aws/aws-sdk-go/private/protocol", - "repository": "https://github.com/aws/aws-sdk-go", - "vcs": "git", - "revision": "966f1a968ba8e260628dfa6be07bcd48d8e98ef6", - "branch": "master", - "path": "/private/protocol", - "notests": true - }, - { - "importpath": "github.com/aws/aws-sdk-go/private/signer/v4", - "repository": "https://github.com/aws/aws-sdk-go", - "vcs": "git", - "revision": "966f1a968ba8e260628dfa6be07bcd48d8e98ef6", - "branch": "master", - "path": "/private/signer/v4", - "notests": true - }, - { - "importpath": "github.com/aws/aws-sdk-go/private/waiter", - "repository": "https://github.com/aws/aws-sdk-go", - "vcs": "git", - "revision": "966f1a968ba8e260628dfa6be07bcd48d8e98ef6", - "branch": "master", - "path": "/private/waiter", - "notests": true - }, - { - "importpath": "github.com/aws/aws-sdk-go/service/kinesis", - "repository": "https://github.com/aws/aws-sdk-go", - "vcs": "git", - "revision": "966f1a968ba8e260628dfa6be07bcd48d8e98ef6", - "branch": "master", - "path": "/service/kinesis", - "notests": true - }, - { - "importpath": "github.com/go-ini/ini", - "repository": "https://github.com/go-ini/ini", - "vcs": "git", - "revision": "12f418cc7edc5a618a51407b7ac1f1f512139df3", - "branch": "master", - "notests": true - }, - { - "importpath": "github.com/go-logfmt/logfmt", - "repository": "https://github.com/go-logfmt/logfmt", - "vcs": "git", - "revision": "08ab82a63ef462ac643ec79e659f023891f588f5", - "branch": "master", - "notests": true - }, - { - "importpath": "github.com/hoisie/redis", - "repository": "https://github.com/hoisie/redis", - "vcs": "git", - "revision": "788f01e396a99c96c8f56338383926f16841ebae", - "branch": "master", - "notests": true - }, - { - "importpath": "github.com/jmespath/go-jmespath", - "repository": "https://github.com/jmespath/go-jmespath", - "vcs": "git", - "revision": "0b12d6b521d83fc7f755e7cfc1b1fbdd35a01a74", - "branch": "master", - "notests": true - }, - { - "importpath": "github.com/jpillora/backoff", - "repository": "https://github.com/jpillora/backoff", - "vcs": "git", - "revision": "0496a6c14df020789376f4d4a261273d5ddb36ec", - "branch": "master", - "notests": true - }, - { - "importpath": "github.com/kr/pretty", - "repository": "https://github.com/kr/pretty", - "vcs": "git", - "revision": "add1dbc86daf0f983cd4a48ceb39deb95c729b67", - "branch": "master", - "notests": true - }, - { - "importpath": "github.com/kr/text", - "repository": "https://github.com/kr/text", - "vcs": "git", - "revision": "bb797dc4fb8320488f47bf11de07a733d7233e1f", - "branch": "master", - "notests": true - }, - { - "importpath": "github.com/rogpeppe/fastuuid", - "repository": "https://github.com/rogpeppe/fastuuid", - "vcs": "git", - "revision": "6724a57986aff9bff1a1770e9347036def7c89f6", - "branch": "master", - "notests": true - }, - { - "importpath": "github.com/tj/go-elastic/batch", - "repository": "https://github.com/tj/go-elastic", - "vcs": "git", - "revision": "6923cdab333be878d768a2b563cd25bc816c3dab", - "branch": "master", - "path": "/batch", - "notests": true - }, - { - "importpath": "github.com/tj/go-kinesis", - "repository": "https://github.com/tj/go-kinesis", - "vcs": "git", - "revision": "677d118cb62c634d6d8dc7c49e979c4d40fac58b", - "branch": "master", - "notests": true - } - ] -} diff --git a/vendor/vendor.json b/vendor/vendor.json new file mode 100644 index 0000000..d5b4d31 --- /dev/null +++ b/vendor/vendor.json @@ -0,0 +1,309 @@ +{ + "comment": "", + "ignore": "test", + "package": [ + { + "checksumSHA1": "Ur88QI//9Ue82g83qvBSakGlzVg=", + "path": "github.com/apex/log", + "revision": "4ea85e918cc8389903d5f12d7ccac5c23ab7d89b", + "revisionTime": "2016-09-05T15:13:04Z" + }, + { + "checksumSHA1": "o5a5xWoaGDKEnNy0W7TikB66lMc=", + "path": "github.com/apex/log/handlers/text", + "revision": "4ea85e918cc8389903d5f12d7ccac5c23ab7d89b", + "revisionTime": "2016-09-05T15:13:04Z" + }, + { + "checksumSHA1": "dSo0vFXJGuTtd6H80q8ZczLszJM=", + "path": "github.com/aws/aws-sdk-go/aws", + "revision": "f34b74c96bfd27df35643adeb14d8431ca047df5", + "revisionTime": "2016-08-17T18:35:19Z" + }, + { + "checksumSHA1": "Y9W+4GimK4Fuxq+vyIskVYFRnX4=", + "path": "github.com/aws/aws-sdk-go/aws/awserr", + "revision": "f34b74c96bfd27df35643adeb14d8431ca047df5", + "revisionTime": "2016-08-17T18:35:19Z" + }, + { + "checksumSHA1": "dkfyy7aRNZ6BmUZ4ZdLIcMMXiPA=", + "path": "github.com/aws/aws-sdk-go/aws/awsutil", + "revision": "f34b74c96bfd27df35643adeb14d8431ca047df5", + "revisionTime": "2016-08-17T18:35:19Z" + }, + { + "checksumSHA1": "H/tMKHZU+Qka6RtYiGB50s2uA0s=", + "path": "github.com/aws/aws-sdk-go/aws/client", + "revision": "f34b74c96bfd27df35643adeb14d8431ca047df5", + "revisionTime": "2016-08-17T18:35:19Z" + }, + { + "checksumSHA1": "ieAJ+Cvp/PKv1LpUEnUXpc3OI6E=", + "path": "github.com/aws/aws-sdk-go/aws/client/metadata", + "revision": "f34b74c96bfd27df35643adeb14d8431ca047df5", + "revisionTime": "2016-08-17T18:35:19Z" + }, + { + "checksumSHA1": "gNWirlrTfSLbOe421hISBAhTqa4=", + "path": "github.com/aws/aws-sdk-go/aws/corehandlers", + "revision": "f34b74c96bfd27df35643adeb14d8431ca047df5", + "revisionTime": "2016-08-17T18:35:19Z" + }, + { + "checksumSHA1": "dNZNaOPfBPnzE2CBnfhXXZ9g9jU=", + "path": "github.com/aws/aws-sdk-go/aws/credentials", + "revision": "f34b74c96bfd27df35643adeb14d8431ca047df5", + "revisionTime": "2016-08-17T18:35:19Z" + }, + { + "checksumSHA1": "KQiUK/zr3mqnAXD7x/X55/iNme0=", + "path": "github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds", + "revision": "f34b74c96bfd27df35643adeb14d8431ca047df5", + "revisionTime": "2016-08-17T18:35:19Z" + }, + { + "checksumSHA1": "NUJUTWlc1sV8b7WjfiYc4JZbXl0=", + "path": "github.com/aws/aws-sdk-go/aws/credentials/endpointcreds", + "revision": "f34b74c96bfd27df35643adeb14d8431ca047df5", + "revisionTime": "2016-08-17T18:35:19Z" + }, + { + "checksumSHA1": "4Ipx+5xN0gso+cENC2MHMWmQlR4=", + "path": "github.com/aws/aws-sdk-go/aws/credentials/stscreds", + "revision": "f34b74c96bfd27df35643adeb14d8431ca047df5", + "revisionTime": "2016-08-17T18:35:19Z" + }, + { + "checksumSHA1": "nCMd1XKjgV21bEl7J8VZFqTV8PE=", + "path": "github.com/aws/aws-sdk-go/aws/defaults", + "revision": "f34b74c96bfd27df35643adeb14d8431ca047df5", + "revisionTime": "2016-08-17T18:35:19Z" + }, + { + "checksumSHA1": "U0SthWum+t9ACanK7SDJOg3dO6M=", + "path": "github.com/aws/aws-sdk-go/aws/ec2metadata", + "revision": "f34b74c96bfd27df35643adeb14d8431ca047df5", + "revisionTime": "2016-08-17T18:35:19Z" + }, + { + "checksumSHA1": "NyUg1P8ZS/LHAAQAk/4C5O4X3og=", + "path": "github.com/aws/aws-sdk-go/aws/request", + "revision": "f34b74c96bfd27df35643adeb14d8431ca047df5", + "revisionTime": "2016-08-17T18:35:19Z" + }, + { + "checksumSHA1": "tBdFneml1Vn7uvezcktsa+hUsGg=", + "path": "github.com/aws/aws-sdk-go/aws/session", + "revision": "f34b74c96bfd27df35643adeb14d8431ca047df5", + "revisionTime": "2016-08-17T18:35:19Z" + }, + { + "checksumSHA1": "7lla+sckQeF18wORAGuU2fFMlp4=", + "path": "github.com/aws/aws-sdk-go/aws/signer/v4", + "revision": "f34b74c96bfd27df35643adeb14d8431ca047df5", + "revisionTime": "2016-08-17T18:35:19Z" + }, + { + "checksumSHA1": "Bm6UrYb2QCzpYseLwwgw6aetgRc=", + "path": "github.com/aws/aws-sdk-go/private/endpoints", + "revision": "f34b74c96bfd27df35643adeb14d8431ca047df5", + "revisionTime": "2016-08-17T18:35:19Z" + }, + { + "checksumSHA1": "wk7EyvDaHwb5qqoOP/4d3cV0708=", + "path": "github.com/aws/aws-sdk-go/private/protocol", + "revision": "f34b74c96bfd27df35643adeb14d8431ca047df5", + "revisionTime": "2016-08-17T18:35:19Z" + }, + { + "checksumSHA1": "L7xWYwx0jNQnzlYHwBS+1q6DcCI=", + "path": "github.com/aws/aws-sdk-go/private/protocol/json/jsonutil", + "revision": "f34b74c96bfd27df35643adeb14d8431ca047df5", + "revisionTime": "2016-08-17T18:35:19Z" + }, + { + "checksumSHA1": "H9TymcQkQnXSXSVfjggiiS4bpzM=", + "path": "github.com/aws/aws-sdk-go/private/protocol/jsonrpc", + "revision": "f34b74c96bfd27df35643adeb14d8431ca047df5", + "revisionTime": "2016-08-17T18:35:19Z" + }, + { + "checksumSHA1": "isoix7lTx4qIq2zI2xFADtti5SI=", + "path": "github.com/aws/aws-sdk-go/private/protocol/query", + "revision": "f34b74c96bfd27df35643adeb14d8431ca047df5", + "revisionTime": "2016-08-17T18:35:19Z" + }, + { + "checksumSHA1": "5xzix1R8prUyWxgLnzUQoxTsfik=", + "path": "github.com/aws/aws-sdk-go/private/protocol/query/queryutil", + "revision": "f34b74c96bfd27df35643adeb14d8431ca047df5", + "revisionTime": "2016-08-17T18:35:19Z" + }, + { + "checksumSHA1": "TW/7U+/8ormL7acf6z2rv2hDD+s=", + "path": "github.com/aws/aws-sdk-go/private/protocol/rest", + "revision": "f34b74c96bfd27df35643adeb14d8431ca047df5", + "revisionTime": "2016-08-17T18:35:19Z" + }, + { + "checksumSHA1": "Y6Db2GGfGD9LPpcJIPj8vXE8BbQ=", + "path": "github.com/aws/aws-sdk-go/private/protocol/restxml", + "revision": "f34b74c96bfd27df35643adeb14d8431ca047df5", + "revisionTime": "2016-08-17T18:35:19Z" + }, + { + "checksumSHA1": "eUEkjyMPAuekKBE4ou+nM9tXEas=", + "path": "github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil", + "revision": "f34b74c96bfd27df35643adeb14d8431ca047df5", + "revisionTime": "2016-08-17T18:35:19Z" + }, + { + "checksumSHA1": "Eo9yODN5U99BK0pMzoqnBm7PCrY=", + "path": "github.com/aws/aws-sdk-go/private/waiter", + "revision": "f34b74c96bfd27df35643adeb14d8431ca047df5", + "revisionTime": "2016-08-17T18:35:19Z" + }, + { + "checksumSHA1": "TtIAgZ+evpkKB5bBYCB69k0wZoU=", + "path": "github.com/aws/aws-sdk-go/service/firehose", + "revision": "f34b74c96bfd27df35643adeb14d8431ca047df5", + "revisionTime": "2016-08-17T18:35:19Z" + }, + { + "checksumSHA1": "2n5/m0ClE4OyQRNdjfLwg+nSY3o=", + "path": "github.com/aws/aws-sdk-go/service/kinesis", + "revision": "f34b74c96bfd27df35643adeb14d8431ca047df5", + "revisionTime": "2016-08-17T18:35:19Z" + }, + { + "checksumSHA1": "fgZ1cdh2T0cWRorIZkMGFDADMQw=", + "path": "github.com/aws/aws-sdk-go/service/kinesis/kinesisiface", + "revision": "f34b74c96bfd27df35643adeb14d8431ca047df5", + "revisionTime": "2016-08-17T18:35:19Z" + }, + { + "checksumSHA1": "imxJucuPrgaPRMPtAgsu+Y7soB4=", + "path": "github.com/aws/aws-sdk-go/service/s3", + "revision": "f34b74c96bfd27df35643adeb14d8431ca047df5", + "revisionTime": "2016-08-17T18:35:19Z" + }, + { + "checksumSHA1": "nH/itbdeFHpl4ysegdtgww9bFSA=", + "path": "github.com/aws/aws-sdk-go/service/sts", + "revision": "f34b74c96bfd27df35643adeb14d8431ca047df5", + "revisionTime": "2016-08-17T18:35:19Z" + }, + { + "checksumSHA1": "zUyQXVCSaV97bbiVZbX1qn8UWm4=", + "path": "github.com/bmizerany/assert", + "revision": "e17e99893cb6509f428e1728281c2ad60a6b31e3", + "revisionTime": "2012-07-16T20:56:30Z" + }, + { + "checksumSHA1": "i7BD7wKsIrix92VtlJ4zQRP4G8c=", + "path": "github.com/crowdmob/goamz/aws", + "revision": "3a06871fe9fc0281ca90f3a7d97258d042ed64c0", + "revisionTime": "2015-01-28T19:49:25Z" + }, + { + "checksumSHA1": "qijq0UWIx8EKPT+GbsbuaZMw/gA=", + "path": "github.com/crowdmob/goamz/s3", + "revision": "3a06871fe9fc0281ca90f3a7d97258d042ed64c0", + "revisionTime": "2015-01-28T19:49:25Z" + }, + { + "checksumSHA1": "FCeEm2BWZV/n4oTy+SGd/k0Ab5c=", + "origin": "github.com/aws/aws-sdk-go/vendor/github.com/go-ini/ini", + "path": "github.com/go-ini/ini", + "revision": "f34b74c96bfd27df35643adeb14d8431ca047df5", + "revisionTime": "2016-08-17T18:35:19Z" + }, + { + "checksumSHA1": "0ZrwvB6KoGPj2PoDNSEJwxQ6Mog=", + "origin": "github.com/aws/aws-sdk-go/vendor/github.com/jmespath/go-jmespath", + "path": "github.com/jmespath/go-jmespath", + "revision": "f34b74c96bfd27df35643adeb14d8431ca047df5", + "revisionTime": "2016-08-17T18:35:19Z" + }, + { + "checksumSHA1": "IXVypCQsDOlWf8dqyFogbOsRdvM=", + "path": "github.com/jpillora/backoff", + "revision": "0496a6c14df020789376f4d4a261273d5ddb36ec", + "revisionTime": "2016-04-14T05:52:04Z" + }, + { + "checksumSHA1": "1YeGotQXMZMqk+mmm8sbBVJywpw=", + "path": "github.com/kr/pretty", + "revision": "e6ac2fc51e89a3249e82157fa0bb7a18ef9dd5bb", + "revisionTime": "2015-05-20T16:35:14Z" + }, + { + "checksumSHA1": "uulQHQ7IsRKqDudBC8Go9J0gtAc=", + "path": "github.com/kr/text", + "revision": "bb797dc4fb8320488f47bf11de07a733d7233e1f", + "revisionTime": "2015-09-05T22:45:08Z" + }, + { + "checksumSHA1": "Tivm2ueYu71B9YxTEyGxe+8ZWgk=", + "path": "github.com/lib/pq", + "revision": "f59175c2986495ff94109dee3835c504a96c3e81", + "revisionTime": "2016-01-27T22:38:42Z" + }, + { + "checksumSHA1": "xppHi82MLqVx1eyQmbhTesAEjx8=", + "path": "github.com/lib/pq/oid", + "revision": "f59175c2986495ff94109dee3835c504a96c3e81", + "revisionTime": "2016-01-27T22:38:42Z" + }, + { + "checksumSHA1": "QI1tJqI+jMmFrCAKcXs+LefgES4=", + "path": "github.com/tj/go-kinesis", + "revision": "817ff40136c6d4909bcff1021e58fdedf788ba23", + "revisionTime": "2016-06-02T03:00:41Z" + }, + { + "checksumSHA1": "+4r0PnLwwyhO5/jvU5R/TEJb4kA=", + "path": "gopkg.in/bsm/ratelimit.v1", + "revision": "db14e161995a5177acef654cb0dd785e8ee8bc22", + "revisionTime": "2016-02-20T15:49:07Z" + }, + { + "checksumSHA1": "JtXTQXRlxRB///NYmPDuMpEpvNI=", + "path": "gopkg.in/redis.v5", + "revision": "854c88a72c8bb9c09936145aef886b7697d6b995", + "revisionTime": "2016-12-03T15:45:52Z" + }, + { + "checksumSHA1": "vQSE4FOH4EvyzYA72w60XOetmVY=", + "path": "gopkg.in/redis.v5/internal", + "revision": "854c88a72c8bb9c09936145aef886b7697d6b995", + "revisionTime": "2016-12-03T15:45:52Z" + }, + { + "checksumSHA1": "2Ek4SixeRSKOX3mUiBMs3Aw+Guc=", + "path": "gopkg.in/redis.v5/internal/consistenthash", + "revision": "854c88a72c8bb9c09936145aef886b7697d6b995", + "revisionTime": "2016-12-03T15:45:52Z" + }, + { + "checksumSHA1": "rJYVKcBrwYUGl7nuuusmZGrt8mY=", + "path": "gopkg.in/redis.v5/internal/hashtag", + "revision": "854c88a72c8bb9c09936145aef886b7697d6b995", + "revisionTime": "2016-12-03T15:45:52Z" + }, + { + "checksumSHA1": "VnsHRPAMRMuhz7/n/85MZwMrchQ=", + "path": "gopkg.in/redis.v5/internal/pool", + "revision": "854c88a72c8bb9c09936145aef886b7697d6b995", + "revisionTime": "2016-12-03T15:45:52Z" + }, + { + "checksumSHA1": "604uyPTNWLBNAnAyNRMiwYHXknA=", + "path": "gopkg.in/redis.v5/internal/proto", + "revision": "854c88a72c8bb9c09936145aef886b7697d6b995", + "revisionTime": "2016-12-03T15:45:52Z" + } + ], + "rootPath": "github.com/harlow/kinesis-connectors" +}