-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
bd78a90
commit 39cf0a6
Showing
13 changed files
with
559 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,3 +22,7 @@ _testmain.go | |
*.exe | ||
*.test | ||
*.prof | ||
|
||
counter | ||
results.bin | ||
*.retry |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
language: go | ||
go: | ||
- 1.6 | ||
- 1.7 | ||
- tip | ||
before_install: | ||
- go get github.com/mattn/goveralls | ||
- go get golang.org/x/tools/cmd/cover | ||
script: | ||
- $HOME/gopath/bin/goveralls -service=travis-ci |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
FROM golang:onbuild |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,27 @@ | ||
# counter | ||
# counter [![Build Status](https://travis-ci.org/phedoreanu/counter.svg?branch=master)](https://travis-ci.org/phedoreanu/counter) [![Coverage Status](https://coveralls.io/repos/github/phedoreanu/counter/badge.svg)](https://coveralls.io/github/phedoreanu/counter) [![Go Report Card](https://goreportcard.com/badge/github.com/phedoreanu/counter)](https://goreportcard.com/report/github.com/phedoreanu/counter) | ||
|
||
[![License](http://img.shields.io/:license-mit-blue.svg)](http://doge.mit-license.org) [![GoDoc](https://godoc.org/github.com/phedoreanu/counter?status.svg)](https://godoc.org/github.com/phedoreanu/counter) | ||
|
||
###Installation | ||
Counter requires Go 1.5 or later. | ||
|
||
###Usage | ||
``` | ||
docker-compose up | ||
``` | ||
|
||
###Unit tests | ||
``` | ||
go test -v -race -cover -parallel 8 -cpu 8 | ||
``` | ||
|
||
###Smoke tests | ||
``` | ||
ansible-playbook smoke-tests.yml | ||
``` | ||
|
||
###Load tests | ||
Start the app and execute: | ||
``` | ||
HOSTNAME=localhost:8080 ./load-tests.sh | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
package db | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"os" | ||
"time" | ||
|
||
"github.com/garyburd/redigo/redis" | ||
"github.com/youtube/vitess/go/pools" | ||
"golang.org/x/net/context" | ||
) | ||
|
||
// Datastore is an interface helper that allows mocking a test database | ||
type Datastore interface { | ||
ReadCounter() int64 | ||
IncrementCounter() | ||
DecrementCounter() | ||
FlushDB() | ||
} | ||
|
||
// DB is a wrapper over the connection pool | ||
type DB struct { | ||
*pools.ResourcePool | ||
} | ||
|
||
// ResourceConn adapts a Redigo connection to a Vitess Resource | ||
type ResourceConn struct { | ||
redis.Conn | ||
} | ||
|
||
// Close closes a connection owned by a Vitess Resource | ||
func (r ResourceConn) Close() { | ||
r.Conn.Close() | ||
} | ||
|
||
// NewPool creates a new Redis connection pool | ||
func NewPool() *DB { | ||
p := pools.NewResourcePool(func() (pools.Resource, error) { | ||
c, err := redis.Dial("tcp", fmt.Sprintf("%s:6379", os.Getenv("REDIS_HOST"))) | ||
return ResourceConn{c}, err | ||
}, 4, 100, time.Minute) | ||
//defer p.Close() | ||
return &DB{p} | ||
} | ||
|
||
// ReadCounter returns the current contents of the counter in the database | ||
func (p *DB) ReadCounter() int64 { | ||
ctx := context.TODO() | ||
r, err := p.Get(ctx) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
defer p.Put(r) | ||
c := r.(ResourceConn) | ||
i64, err := redis.Int64(c.Do("GET", "counter")) | ||
if err != nil { | ||
fmt.Println(err) | ||
} | ||
return i64 | ||
} | ||
|
||
// IncrementCounter increments the counter by 1 | ||
func (p *DB) IncrementCounter() { | ||
ctx := context.TODO() | ||
r, err := p.Get(ctx) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
defer p.Put(r) | ||
c := r.(ResourceConn) | ||
c.Send("MULTI") | ||
c.Send("INCR", "counter") | ||
//c.Send("EXEC") | ||
_, err = c.Do("EXEC") | ||
if err != nil { | ||
fmt.Println(err) | ||
} | ||
} | ||
|
||
// DecrementCounter decrements the counter by 1 | ||
func (p *DB) DecrementCounter() { | ||
ctx := context.TODO() | ||
r, err := p.Get(ctx) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
defer p.Put(r) | ||
c := r.(ResourceConn) | ||
c.Send("MULTI") | ||
c.Send("DECR", "counter") | ||
//c.Send("EXEC") | ||
_, err = c.Do("EXEC") | ||
if err != nil { | ||
fmt.Println(err) | ||
} | ||
} | ||
|
||
// FlushDB flushed the DB | ||
func (p *DB) FlushDB() { | ||
ctx := context.TODO() | ||
r, err := p.Get(ctx) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
defer p.Put(r) | ||
c := r.(ResourceConn) | ||
c.Send("MULTI") | ||
c.Send("FLUSHDB") | ||
rep, err := c.Do("EXEC") | ||
if err != nil { | ||
fmt.Println(err) | ||
} | ||
fmt.Println(rep) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
version: '2' | ||
services: | ||
counter: | ||
environment: | ||
- REDIS_HOST=redis | ||
ports: | ||
- 8080:8080 | ||
image: 'phedoreanu/counter:latest' | ||
links: | ||
- redis | ||
redis: | ||
image: 'redis:latest' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
#!/bin/bash | ||
|
||
if [ ! -d "$DIRECTORY" ]; then | ||
go get -u github.com/tsenart/vegeta | ||
fi | ||
|
||
echo "GET http://${HOSTNAME}/get" | vegeta attack -duration=30s | tee results.bin | vegeta report |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"net/http" | ||
|
||
"github.com/phedoreanu/counter/db" | ||
"github.com/phedoreanu/counter/synced" | ||
) | ||
|
||
// Env is a dependency injection helper | ||
type Env struct { | ||
db db.Datastore | ||
c chan int64 | ||
synced *synced.Synced | ||
} | ||
|
||
// GetHandler returns the number of hits to /get endpoint | ||
func (env *Env) handleGet(w http.ResponseWriter, _ *http.Request) { | ||
go func() { | ||
env.c <- env.synced.Increment() | ||
}() | ||
fmt.Fprint(w, env.synced.Read()) | ||
} | ||
|
||
// StatusHandler returns the current contents of the counter in the database | ||
func (env *Env) handleStatus(w http.ResponseWriter, _ *http.Request) { | ||
fmt.Fprint(w, env.db.ReadCounter()) | ||
} | ||
|
||
// SyncCounter increments the counter in the database | ||
// and every 10 requests to /get flips and decrements the counter | ||
func (env *Env) SyncCounter(hits int64) { | ||
switch env.synced.GetDirection() { | ||
case true: | ||
env.db.DecrementCounter() | ||
case false: | ||
env.db.IncrementCounter() | ||
} | ||
if hits%10 == 0 { | ||
env.synced.Reverse() | ||
} | ||
} | ||
|
||
func main() { | ||
env := Env{ | ||
db: db.NewPool(), | ||
c: make(chan int64), | ||
synced: synced.NewSynced(), | ||
} | ||
env.db.FlushDB() | ||
|
||
go func() { | ||
for { | ||
env.SyncCounter(<-env.c) | ||
} | ||
}() | ||
|
||
http.HandleFunc("/get", env.handleGet) | ||
http.HandleFunc("/status", env.handleStatus) | ||
|
||
log.Fatal(http.ListenAndServe(":8080", nil)) | ||
} |
Oops, something went wrong.