go-gentle

module
v3.0.8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 24, 2017 License: MIT

README

Go-gentle

GoDoc Build Status Go Report Coverage Status

Talk to external services like a gentleman.

Intro

Package gentle defines Stream and Handler interfaces and provides composable resilient implementations(conveniently called gentle-ments). Please refer to this overview.

Package extra provides supplement components(logger adaptors, metric collectors, etc.) for gentle.

Example

Error handling is omitted for brevity.

// GameScore implements gentle.Message interface
type GameScore struct {
	id string // better to be unique for tracing it in log
	Score int
}

// a gentle.Message must support ID
func (s GameScore) ID() string {
	return s.id
}

// scoreStream is a gentle.Stream that wraps an API call to an external service for
// getting game scores.
// For simple cases that the logic can be defined entirely in a function, we can
// simply define it to be a gentle.SimpleStream.
var scoreStream gentle.SimpleStream = func(_ context.Context) (gentle.Message, error) {
	// simulate a result from an external service
	return &GameScore{
		id: "",
		Score: rand.Intn(100),
	}, nil
}

// DbWriter is a gentle.Handler that writes scores to the database.
// Instead of using gentle.SimpleHandler, we define a struct explicitly
// implementing gentle.Handler interface.
type DbWriter struct {
	db *sql.DB
	table string
}

func (h *DbWriter) Handle(_ context.Context, msg gentle.Message) (gentle.Message, error) {
	gameScore := msg.(*GameScore)
	statement := fmt.Sprintf("INSERT INTO %s (score, date) VALUES (?, DATETIME());", h.table)
	_, err := h.db.Exec(statement, gameScore.Score)
	if err != nil {
		return nil, err
	}
	return msg, nil
}

For not overwhelming the score-query service and the database, we use gentle-ments(resilience Streams/Handlers defined in package gentle).

func main() {
	db, _ := sql.Open("sqlite3", "scores.sqlite")
	defer db.Close()
	db.Exec("DROP TABLE IF EXISTS game;")
	db.Exec("CREATE TABLE game (score INTEGER, date DATETIME);")

	dbWriter := &DbWriter{
		db: db,
		table: "game",
	}

	// Rate-limit the queries while allowing burst of some
	gentleScoreStream := gentle.NewRateLimitedStream(
		gentle.NewRateLimitedStreamOpts("myApp", "rlQuery",
			gentle.NewTokenBucketRateLimit(500*time.Millisecond, 5)),
		scoreStream)

	// Limit concurrent writes to Db
	limitedDbWriter := gentle.NewBulkheadHandler(
		gentle.NewBulkheadHandlerOpts("myApp", "bkWrite", 16),
		dbWriter)

	// Constantly backing off when limitedDbWriter returns an error
	backoffFactory := gentle.NewConstBackOffFactory(
		gentle.NewConstBackOffFactoryOpts(500*time.Millisecond, 5*time.Minute))
	gentleDbWriter := gentle.NewRetryHandler(
		gentle.NewRetryHandlerOpts("myApp", "rtWrite", backoffFactory),
		limitedDbWriter)

	// Compose the final Stream
	stream := gentle.AppendHandlersStream(gentleScoreStream, gentleDbWriter)

	// Keep fetching scores from the remote service to our database.
	// The amount of simultaneous go-routines are capped by the size of ticketPool.
	ticketPool := make(chan struct{}, 1000)
	for {
		ticketPool <- struct{}{}
		go func() {
			defer func(){ <-ticketPool }()
			stream.Get(context.Background())
		}()
	}
}

Full example

Install

The master branch is considered unstable. Always depend on semantic versioning and verdor this library.

If you're using glide, simply run:

glide get gopkg.in/cfchou/go-gentle.v3
glide update

If you're not using package management tools, then

go get gopkg.in/cfchou/go-gentle.v3

Other features

  • Logging: Gentle-ments log extensively. Users can plug in their logger library of choice. Package extra/log provides adaptors for log15 and logrus.
  • Metrics: Gentle-ments send metrics in aid of monitoring. Users can plug in their metric collector of choice. Package extra/metric provides collectors of prometheus and statsd.
  • OpenTracing: Gentle-ments integrates OpenTracing. Users can choose a variety of backends that support OpenTracing. Package extra/tracing provides an example of using Uber's jaeger as the backend.

Reference

Directories

Path Synopsis
Package extra provides supplement components for the sibling package gentle(https://godoc.org/github.com/cfchou/go-gentle/gentle).
Package extra provides supplement components for the sibling package gentle(https://godoc.org/github.com/cfchou/go-gentle/gentle).
log
Package log contains adaptors of gentle.Logger for different logging libraries.
Package log contains adaptors of gentle.Logger for different logging libraries.
metric
Package metric contains adaptors of metrics collectors used for gentle-ments in gentle.
Package metric contains adaptors of metrics collectors used for gentle-ments in gentle.
Package gentle defines Stream and Handler interfaces and provides composable resilient implementations of them.
Package gentle defines Stream and Handler interfaces and provides composable resilient implementations of them.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL