Skip to content

Commit f70ff2c

Browse files
authored
Merge pull request #1 from gomicro/multiblocker
Multiblocker and DB Blocker
2 parents 554365c + 1e1c3b3 commit f70ff2c

File tree

200 files changed

+197916
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

200 files changed

+197916
-0
lines changed

.travis.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
language: go
2+
go:
3+
- 1.9
4+
- tip
5+
script:
6+
- go test -v $(go list ./... | grep -v /vendor/)
7+
notifications:
8+
slack:
9+
secure: BBtX6Qg8Dp63u6sfcEK7xeqBAL8ok/RI7b47zBEfWI/HYkMAyF+cqc0PobgIoVelfoUNDZVxV20hoLIeE9GpI0ifcfS61LLU+Mx0Kt9Zczu31oEmZR0wGosxvfi0abnFVsmsxvZ+PqtTgy7JlqTgAguLQFwDY0lun77sGLld9DVE0UFhHThXuj5CeatvX7z7bxR8fqdHwFxO5gLgPWNoNmFScGI8+CcXH4J7QRs8Coos6sPYvflFO8t8tSeDYXZ3RYBh5UxEDjIsRkSfSvWqCq2BBEmLTJcsJ9lxzF6nTloXujO3uDSomwHD9j1qJAuFzKaUjFoBmJqAWm+Yt6fhiPeQkxukllWtBaaXk70msbxcrlEh5IfnDrpzd+hSCrDJoLj6hReV5ga5cVicNuxLIYVs0ELtB5yKhh+3e/VJMr6vNFGrw6otHBX4PdoRk7aEOyQ9fLI0o1nmyiWoxU8wx2JKUsj0Ze8xW7puJbPdVTJyncw3J0iMcYUtNdQN+8+Jyqk6yMm5Di/Is0dBzYW45w9AW/ZOhjQ037erTk2SpAIK01xElIKbsiFt2bSBmZwGpI0zT34W5IHEZCRJyQD/c9d2Gs2lGcH9YjAxLDhEH48zyqRV6nO4J6uZM3BhIzBwiOUPeoikJoLXIh+Dd96iFYGWMigaV99muO/N4rl1pho=

Gopkg.lock

Lines changed: 80 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Gopkg.toml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Gopkg.toml example
2+
#
3+
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
4+
# for detailed Gopkg.toml documentation.
5+
#
6+
# required = ["github.com/user/thing/cmd/thing"]
7+
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
8+
#
9+
# [[constraint]]
10+
# name = "github.com/user/project"
11+
# version = "1.0.0"
12+
#
13+
# [[constraint]]
14+
# name = "github.com/user/project2"
15+
# branch = "dev"
16+
# source = "github.com/myfork/project2"
17+
#
18+
# [[override]]
19+
# name = "github.com/x/y"
20+
# version = "2.4.0"
21+
#
22+
# [prune]
23+
# non-go = false
24+
# go-tests = true
25+
# unused-packages = true
26+
27+
28+
[[constraint]]
29+
name = "github.com/franela/goblin"
30+
version = "0.0.2"
31+
32+
[[constraint]]
33+
name = "github.com/onsi/gomega"
34+
version = "1.4.1"
35+
36+
[[constraint]]
37+
name = "gopkg.in/DATA-DOG/go-sqlmock.v1"
38+
version = "1.3.0"
39+
40+
[prune]
41+
go-tests = true
42+
unused-packages = true

blocker.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package blockit
2+
3+
// Blocker represents an object that will have a Blockit function as a method
4+
// for determining when the object is done with a given task.
5+
type Blocker interface {
6+
Blockit() <-chan bool
7+
}

db/db.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package db
2+
3+
import (
4+
"database/sql"
5+
"time"
6+
)
7+
8+
// Blocker represents a SQL database connection to monitor for connectivity
9+
// and block until a connection is established.
10+
type Blocker struct {
11+
db *sql.DB
12+
}
13+
14+
// New takes a SQL database object and returns a newly instantiated Blocker
15+
func New(db *sql.DB) *Blocker {
16+
return &Blocker{db: db}
17+
}
18+
19+
// Blockit meets the blocker interface. It returns a read only channel that will
20+
// receive true when the database is connected.
21+
func (d *Blocker) Blockit() <-chan bool {
22+
connected := make(chan bool)
23+
24+
go func() {
25+
for {
26+
err := d.db.Ping()
27+
if err != nil {
28+
<-time.After(1 * time.Second)
29+
continue
30+
}
31+
32+
connected <- true
33+
close(connected)
34+
35+
break
36+
}
37+
}()
38+
39+
return connected
40+
}

db/db_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package db_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/gomicro/blockit/db"
7+
8+
. "github.com/franela/goblin"
9+
. "github.com/onsi/gomega"
10+
"gopkg.in/DATA-DOG/go-sqlmock.v1"
11+
)
12+
13+
func TestDefaultBlockers(t *testing.T) {
14+
g := Goblin(t)
15+
RegisterFailHandler(func(m string, _ ...int) { g.Fail(m) })
16+
17+
g.Describe("DB Blocking", func() {
18+
g.It("should block until connected to the db", func() {
19+
mockDB, _, _ := sqlmock.New()
20+
21+
b := db.New(mockDB)
22+
Eventually(<-b.Blockit()).Should(BeTrue())
23+
})
24+
})
25+
}

multiblocker.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package blockit
2+
3+
// MultiBlocker represent many blockers to monitor and determine when they are
4+
// done.
5+
type MultiBlocker struct {
6+
blockers []Blocker
7+
}
8+
9+
// Add takes one to many blockers to append into the multiblocker
10+
func (b *MultiBlocker) Add(blocker ...Blocker) {
11+
b.blockers = append(b.blockers, blocker...)
12+
}
13+
14+
// Blockit meets the blocker interface and summarizes multiple blockers into a
15+
// single channel for blocking on.
16+
func (b *MultiBlocker) Blockit() <-chan bool {
17+
out := make(chan bool)
18+
19+
dones := make([]chan bool, len(b.blockers))
20+
for i := range dones {
21+
dones[i] = make(chan bool)
22+
}
23+
24+
for i := range b.blockers {
25+
go func(j int) {
26+
<-b.blockers[j].Blockit()
27+
dones[j] <- true
28+
}(i)
29+
}
30+
31+
go func() {
32+
done := false
33+
for i := range dones {
34+
done = <-dones[i]
35+
}
36+
37+
if done {
38+
out <- true
39+
}
40+
close(out)
41+
}()
42+
43+
return out
44+
}

multiblocker_test.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package blockit_test
2+
3+
import (
4+
"testing"
5+
"time"
6+
7+
"github.com/gomicro/blockit"
8+
"github.com/gomicro/blockit/db"
9+
10+
. "github.com/franela/goblin"
11+
. "github.com/onsi/gomega"
12+
"gopkg.in/DATA-DOG/go-sqlmock.v1"
13+
)
14+
15+
func TestMultiBlocker(t *testing.T) {
16+
g := Goblin(t)
17+
RegisterFailHandler(func(m string, _ ...int) { g.Fail(m) })
18+
19+
g.Describe("MultiBlocker", func() {
20+
g.Describe("Multiple Blockers", func() {
21+
g.It("should block with several blockers", func() {
22+
b := blockit.MultiBlocker{}
23+
24+
f := &foo{}
25+
b.Add(f)
26+
27+
ba := &bar{}
28+
b.Add(ba)
29+
30+
Eventually(<-b.Blockit()).Should(BeTrue())
31+
})
32+
})
33+
34+
g.Describe("DB Blocker", func() {
35+
g.It("should work in a multiblocker", func() {
36+
mockDB, _, _ := sqlmock.New()
37+
38+
b := blockit.MultiBlocker{}
39+
b.Add(db.New(mockDB))
40+
Eventually(<-b.Blockit()).Should(BeTrue())
41+
})
42+
})
43+
})
44+
}
45+
46+
type foo struct{}
47+
type bar struct{}
48+
49+
func (f *foo) Blockit() <-chan bool {
50+
out := make(chan bool)
51+
52+
go func() {
53+
<-time.After(1 * time.Second)
54+
close(out)
55+
}()
56+
57+
return out
58+
}
59+
60+
func (b *bar) Blockit() <-chan bool {
61+
out := make(chan bool)
62+
63+
go func() {
64+
<-time.After(3 * time.Second)
65+
close(out)
66+
}()
67+
68+
return out
69+
}

vendor/github.com/franela/goblin/.gitignore

Lines changed: 22 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/franela/goblin/.travis.yml

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)