Use golint to update Golang styles
* Update comments and return statements * Adjust usage of Kinesis library (upgraded local source)
This commit is contained in:
parent
02a7c648a3
commit
8e8ee5af73
11 changed files with 47 additions and 41 deletions
|
|
@ -1,9 +1,9 @@
|
||||||
package connector
|
package connector
|
||||||
|
|
||||||
// A basic implementation of the Filter interface that returns true for all records.
|
// AllPassFilter an implementation of the Filter interface that returns true for all records.
|
||||||
type AllPassFilter struct{}
|
type AllPassFilter struct{}
|
||||||
|
|
||||||
// Returns true for all records.
|
// KeepRecord returns true for all records.
|
||||||
func (b *AllPassFilter) KeepRecord(r interface{}) bool {
|
func (b *AllPassFilter) KeepRecord(r interface{}) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package connector
|
package connector
|
||||||
|
|
||||||
// Used by Pipeline.ProcessShard when they want to checkpoint their progress.
|
// Checkpoint is used by Pipeline.ProcessShard when they want to checkpoint their progress.
|
||||||
// The Kinesis Connector Library will pass an object implementing this interface to ProcessShard,
|
// The Kinesis Connector Library will pass an object implementing this interface to ProcessShard,
|
||||||
// so they can checkpoint their progress.
|
// so they can checkpoint their progress.
|
||||||
type Checkpoint interface {
|
type Checkpoint interface {
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,7 @@
|
||||||
package connector
|
package connector
|
||||||
|
|
||||||
// The Filter is associated with an Buffer. The Buffer may use the result of calling the
|
// Filter is an interface used for determinint whether to buffer records.
|
||||||
// KeepRecord() method to decide whether to store a record or discard it.
|
// Returns false if you don't want to hold on to the record.
|
||||||
|
|
||||||
// A method enabling the buffer to filter records. Return false if you don't want to hold on to
|
|
||||||
// the record.
|
|
||||||
type Filter interface {
|
type Filter interface {
|
||||||
KeepRecord(r interface{}) bool
|
KeepRecord(r interface{}) bool
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,8 @@ import (
|
||||||
"github.com/sendgridlabs/go-kinesis"
|
"github.com/sendgridlabs/go-kinesis"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This struct is used by the main application to configure instances of the user's implemented pipline.
|
// Pipeline is used as a record processor to configure a pipline.
|
||||||
|
//
|
||||||
// The user should implement this such that each method returns a configured implementation of each
|
// The user should implement this such that each method returns a configured implementation of each
|
||||||
// interface. It has a data type (Model) as Records come in as a byte[] and are transformed to a Model.
|
// interface. It has a data type (Model) as Records come in as a byte[] and are transformed to a Model.
|
||||||
// Then they are buffered in Model form and when the buffer is full, Models's are passed to the emitter.
|
// Then they are buffered in Model form and when the buffer is full, Models's are passed to the emitter.
|
||||||
|
|
@ -20,6 +21,8 @@ type Pipeline struct {
|
||||||
Transformer Transformer
|
Transformer Transformer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ProcessShard kicks off the process of a Kinesis Shard.
|
||||||
|
// It is a long running process that will continue to read from the shard.
|
||||||
func (p Pipeline) ProcessShard(ksis *kinesis.Kinesis, shardID string) {
|
func (p Pipeline) ProcessShard(ksis *kinesis.Kinesis, shardID string) {
|
||||||
args := kinesis.NewArgs()
|
args := kinesis.NewArgs()
|
||||||
args.Add("ShardId", shardID)
|
args.Add("ShardId", shardID)
|
||||||
|
|
@ -54,7 +57,7 @@ func (p Pipeline) ProcessShard(ksis *kinesis.Kinesis, shardID string) {
|
||||||
|
|
||||||
if len(recordSet.Records) > 0 {
|
if len(recordSet.Records) > 0 {
|
||||||
for _, v := range recordSet.Records {
|
for _, v := range recordSet.Records {
|
||||||
data, err := v.GetData()
|
data := v.GetData()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("GetData ERROR: %v\n", err)
|
fmt.Printf("GetData ERROR: %v\n", err)
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
package connector
|
package connector
|
||||||
|
|
||||||
// This struct is a basic implementation of the Buffer interface. It is a wrapper on a buffer of
|
// RecordBuffer is a basic implementation of the Buffer interface.
|
||||||
// records that are periodically flushed. It is configured with an implementation of Filter that
|
// It buffer's records and answers questions on when it should be periodically flushed.
|
||||||
// decides whether a record will be added to the buffer to be emitted.
|
|
||||||
type RecordBuffer struct {
|
type RecordBuffer struct {
|
||||||
NumRecordsToBuffer int
|
NumRecordsToBuffer int
|
||||||
|
|
||||||
|
|
@ -12,7 +11,7 @@ type RecordBuffer struct {
|
||||||
sequencesInBuffer []string
|
sequencesInBuffer []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adds a message to the buffer.
|
// ProcessRecord adds a message to the buffer.
|
||||||
func (b *RecordBuffer) ProcessRecord(record interface{}, sequenceNumber string) {
|
func (b *RecordBuffer) ProcessRecord(record interface{}, sequenceNumber string) {
|
||||||
if len(b.sequencesInBuffer) == 0 {
|
if len(b.sequencesInBuffer) == 0 {
|
||||||
b.firstSequenceNumber = sequenceNumber
|
b.firstSequenceNumber = sequenceNumber
|
||||||
|
|
@ -26,17 +25,17 @@ func (b *RecordBuffer) ProcessRecord(record interface{}, sequenceNumber string)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the records in the buffer.
|
// Records returns the records in the buffer.
|
||||||
func (b *RecordBuffer) Records() []interface{} {
|
func (b *RecordBuffer) Records() []interface{} {
|
||||||
return b.recordsInBuffer
|
return b.recordsInBuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the number of messages in the buffer.
|
// NumRecordsInBuffer returns the number of messages in the buffer.
|
||||||
func (b RecordBuffer) NumRecordsInBuffer() int {
|
func (b RecordBuffer) NumRecordsInBuffer() int {
|
||||||
return len(b.sequencesInBuffer)
|
return len(b.sequencesInBuffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flushes the content in the buffer and resets the sequence counter.
|
// Flush empties the buffer and resets the sequence counter.
|
||||||
func (b *RecordBuffer) Flush() {
|
func (b *RecordBuffer) Flush() {
|
||||||
b.recordsInBuffer = b.recordsInBuffer[:0]
|
b.recordsInBuffer = b.recordsInBuffer[:0]
|
||||||
b.sequencesInBuffer = b.sequencesInBuffer[:0]
|
b.sequencesInBuffer = b.sequencesInBuffer[:0]
|
||||||
|
|
@ -52,17 +51,17 @@ func (b *RecordBuffer) sequenceExists(sequenceNumber string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determines if the buffer has reached its target size.
|
// ShouldFlush determines if the buffer has reached its target size.
|
||||||
func (b *RecordBuffer) ShouldFlush() bool {
|
func (b *RecordBuffer) ShouldFlush() bool {
|
||||||
return len(b.sequencesInBuffer) >= b.NumRecordsToBuffer
|
return len(b.sequencesInBuffer) >= b.NumRecordsToBuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the sequence number of the first message in the buffer.
|
// FirstSequenceNumber returns the sequence number of the first message in the buffer.
|
||||||
func (b *RecordBuffer) FirstSequenceNumber() string {
|
func (b *RecordBuffer) FirstSequenceNumber() string {
|
||||||
return b.firstSequenceNumber
|
return b.firstSequenceNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the sequence number of the last message in the buffer.
|
// LastSequenceNumber returns the sequence number of the last message in the buffer.
|
||||||
func (b *RecordBuffer) LastSequenceNumber() string {
|
func (b *RecordBuffer) LastSequenceNumber() string {
|
||||||
return b.lastSequenceNumber
|
return b.lastSequenceNumber
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ func (r TestRecord) ToDelimitedString() string {
|
||||||
return "test"
|
return "test"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r TestRecord) ToJson() []byte {
|
func (r TestRecord) ToJSON() []byte {
|
||||||
return []byte("test")
|
return []byte("test")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ import (
|
||||||
"github.com/hoisie/redis"
|
"github.com/hoisie/redis"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A Redis implementation of the Checkpont interface. This class is used to enable the Pipeline.ProcessShard
|
// RedisCheckpoint implements the Checkpont interface.
|
||||||
// to checkpoint their progress.
|
// This class is used to enable the Pipeline.ProcessShard to checkpoint their progress.
|
||||||
type RedisCheckpoint struct {
|
type RedisCheckpoint struct {
|
||||||
AppName string
|
AppName string
|
||||||
StreamName string
|
StreamName string
|
||||||
|
|
@ -16,32 +16,33 @@ type RedisCheckpoint struct {
|
||||||
sequenceNumber string
|
sequenceNumber string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether a checkpoint for a particular Shard exists. Typically used to determine whether we should
|
// CheckpointExists determines if a checkpoint for a particular Shard exists.
|
||||||
// start processing the shard with TRIM_HORIZON or AFTER_SEQUENCE_NUMBER (if checkpoint 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 {
|
func (c *RedisCheckpoint) CheckpointExists(shardID string) bool {
|
||||||
val, _ := c.client.Get(c.key(shardID))
|
val, _ := c.client.Get(c.key(shardID))
|
||||||
|
|
||||||
if val != nil && string(val) != "" {
|
if val != nil && string(val) != "" {
|
||||||
c.sequenceNumber = string(val)
|
c.sequenceNumber = string(val)
|
||||||
return true
|
return true
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the current checkpoint stored for the specified shard.
|
// SequenceNumber returns the current checkpoint stored for the specified shard.
|
||||||
func (c *RedisCheckpoint) SequenceNumber() string {
|
func (c *RedisCheckpoint) SequenceNumber() string {
|
||||||
return c.sequenceNumber
|
return c.sequenceNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
// Record a checkpoint for a shard (e.g. sequence number of last record processed by application).
|
// 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.
|
// Upon failover, record processing is resumed from this point.
|
||||||
func (c *RedisCheckpoint) SetCheckpoint(shardID string, sequenceNumber string) {
|
func (c *RedisCheckpoint) SetCheckpoint(shardID string, sequenceNumber string) {
|
||||||
c.client.Set(c.key(shardID), []byte(sequenceNumber))
|
c.client.Set(c.key(shardID), []byte(sequenceNumber))
|
||||||
c.sequenceNumber = sequenceNumber
|
c.sequenceNumber = sequenceNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a unique Redis key for storage of Checkpoint.
|
// key generates a unique Redis key for storage of Checkpoint.
|
||||||
func (c *RedisCheckpoint) key(shardID string) string {
|
func (c *RedisCheckpoint) key(shardID string) string {
|
||||||
return fmt.Sprintf("%v:checkpoint:%v:%v", c.AppName, c.StreamName, shardID)
|
return fmt.Sprintf("%v:checkpoint:%v:%v", c.AppName, c.StreamName, shardID)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,11 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
// Postgres package is used when sql.Open is called
|
||||||
_ "github.com/lib/pq"
|
_ "github.com/lib/pq"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This struct is an implementation of Emitter that buffered batches of records into Redshift one by one.
|
// RedshiftEmitter is an implementation of Emitter that buffered batches of records into Redshift one by one.
|
||||||
// It first emits records into S3 and then perfors the Redshift JSON COPY command. S3 storage of buffered
|
// It first emits records into S3 and then perfors the Redshift JSON COPY command. S3 storage of buffered
|
||||||
// data achieved using the S3Emitter. A link to jsonpaths must be provided when configuring the struct.
|
// data achieved using the S3Emitter. A link to jsonpaths must be provided when configuring the struct.
|
||||||
type RedshiftEmitter struct {
|
type RedshiftEmitter struct {
|
||||||
|
|
@ -21,8 +22,8 @@ type RedshiftEmitter struct {
|
||||||
TableName string
|
TableName string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invoked when the buffer is full. This method leverages the S3Emitter and then issues a copy command to
|
// Emit is invoked when the buffer is full. This method leverages the S3Emitter and
|
||||||
// Redshift data store.
|
// then issues a copy command to Redshift data store.
|
||||||
func (e RedshiftEmitter) Emit(b Buffer, t Transformer) {
|
func (e RedshiftEmitter) Emit(b Buffer, t Transformer) {
|
||||||
s3Emitter := S3Emitter{S3Bucket: e.S3Bucket}
|
s3Emitter := S3Emitter{S3Bucket: e.S3Bucket}
|
||||||
s3Emitter.Emit(b, t)
|
s3Emitter.Emit(b, t)
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,9 @@ import (
|
||||||
"github.com/crowdmob/goamz/s3"
|
"github.com/crowdmob/goamz/s3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This implementation of Emitter is used to store files from a Kinesis stream in S3. The use of
|
// S3Emitter is an implementation of Emitter used to store files from a Kinesis stream in S3.
|
||||||
// this struct requires the configuration of an S3 bucket/endpoint. When the buffer is full, this
|
//
|
||||||
|
// The use of this struct requires the configuration of an S3 bucket/endpoint. When the buffer is full, this
|
||||||
// struct's Emit method adds the contents of the buffer to S3 as one file. The filename is generated
|
// struct's Emit method adds the contents of the buffer to S3 as one file. The filename is generated
|
||||||
// from the first and last sequence numbers of the records contained in that file separated by a
|
// from the first and last sequence numbers of the records contained in that file separated by a
|
||||||
// dash. This struct requires the configuration of an S3 bucket and endpoint.
|
// dash. This struct requires the configuration of an S3 bucket and endpoint.
|
||||||
|
|
@ -18,14 +19,14 @@ type S3Emitter struct {
|
||||||
S3Bucket string
|
S3Bucket string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generates a file name based on the First and Last sequence numbers from the buffer. The current
|
// S3FileName generates a file name based on the First and Last sequence numbers from the buffer. The current
|
||||||
// UTC date (YYYY-MM-DD) is base of the path to logically group days of batches.
|
// UTC date (YYYY-MM-DD) is base of the path to logically group days of batches.
|
||||||
func (e S3Emitter) S3FileName(firstSeq string, lastSeq string) string {
|
func (e S3Emitter) S3FileName(firstSeq string, lastSeq string) string {
|
||||||
date := time.Now().UTC().Format("2006-01-02")
|
date := time.Now().UTC().Format("2006-01-02")
|
||||||
return fmt.Sprintf("/%v/%v-%v.txt", date, firstSeq, lastSeq)
|
return fmt.Sprintf("/%v/%v-%v.txt", date, firstSeq, lastSeq)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invoked when the buffer is full. This method emits the set of filtered records.
|
// Emit is invoked when the buffer is full. This method emits the set of filtered records.
|
||||||
func (e S3Emitter) Emit(b Buffer, t Transformer) {
|
func (e S3Emitter) Emit(b Buffer, t Transformer) {
|
||||||
auth, _ := aws.EnvAuth()
|
auth, _ := aws.EnvAuth()
|
||||||
s3Con := s3.New(auth, aws.USEast)
|
s3Con := s3.New(auth, aws.USEast)
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,14 @@
|
||||||
package connector
|
package connector
|
||||||
|
|
||||||
|
// StringToStringTransformer an implemenation of Transformer interface.
|
||||||
type StringToStringTransformer struct{}
|
type StringToStringTransformer struct{}
|
||||||
|
|
||||||
|
// ToRecord takes a byte array and returns a string.
|
||||||
func (t StringToStringTransformer) ToRecord(data []byte) interface{} {
|
func (t StringToStringTransformer) ToRecord(data []byte) interface{} {
|
||||||
return string(data)
|
return string(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FromRecord takes an string and returns a byte array.
|
||||||
func (t StringToStringTransformer) FromRecord(s interface{}) []byte {
|
func (t StringToStringTransformer) FromRecord(s interface{}) []byte {
|
||||||
return []byte(s.(string))
|
return []byte(s.(string))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
9
utils.go
9
utils.go
|
|
@ -46,7 +46,7 @@ func upcaseInitial(str string) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// Opens the file path and loads config values into the sturct.
|
// LoadConfig opens the file path and loads config values into the sturct.
|
||||||
func LoadConfig(config interface{}, filename string) error {
|
func LoadConfig(config interface{}, filename string) error {
|
||||||
lines, err := readLines(filename)
|
lines, err := readLines(filename)
|
||||||
|
|
||||||
|
|
@ -89,7 +89,8 @@ func LoadConfig(config interface{}, filename string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates a new Kinesis stream (uses existing stream if exists) and waits for it to become available.
|
// CreateAndWaitForStreamToBecomeAvailable creates a new Kinesis stream (uses
|
||||||
|
// existing stream if exists) and waits for it to become available.
|
||||||
func CreateAndWaitForStreamToBecomeAvailable(k *kinesis.Kinesis, streamName string, shardCount int) {
|
func CreateAndWaitForStreamToBecomeAvailable(k *kinesis.Kinesis, streamName string, shardCount int) {
|
||||||
if !StreamExists(k, streamName) {
|
if !StreamExists(k, streamName) {
|
||||||
err := k.CreateStream(streamName, shardCount)
|
err := k.CreateStream(streamName, shardCount)
|
||||||
|
|
@ -119,7 +120,7 @@ func CreateAndWaitForStreamToBecomeAvailable(k *kinesis.Kinesis, streamName stri
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if a Kinesis stream exists.
|
// StreamExists checks if a Kinesis stream exists.
|
||||||
func StreamExists(k *kinesis.Kinesis, streamName string) bool {
|
func StreamExists(k *kinesis.Kinesis, streamName string) bool {
|
||||||
args := kinesis.NewArgs()
|
args := kinesis.NewArgs()
|
||||||
resp, _ := k.ListStreams(args)
|
resp, _ := k.ListStreams(args)
|
||||||
|
|
@ -131,7 +132,7 @@ func StreamExists(k *kinesis.Kinesis, streamName string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete a Kinesis stream.
|
// DeleteStream deletes a current Kinesis stream.
|
||||||
func DeleteStream(k *kinesis.Kinesis, streamName string) {
|
func DeleteStream(k *kinesis.Kinesis, streamName string) {
|
||||||
err := k.DeleteStream("test")
|
err := k.DeleteStream("test")
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue