Project has been created.
This commit is contained in:
commit
f863bd455f
68
.gitignore
vendored
Normal file
68
.gitignore
vendored
Normal file
|
@ -0,0 +1,68 @@
|
|||
# Created by .ignore support plugin (hsz.mobi)
|
||||
### JetBrains template
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff:
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/dictionaries
|
||||
|
||||
# Sensitive or high-churn files:
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.xml
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
|
||||
# Gradle:
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Mongo Explorer plugin:
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
## File-based project format:
|
||||
*.iws
|
||||
|
||||
## Plugin-specific files:
|
||||
|
||||
# IntelliJ
|
||||
/out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
### Go template
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
|
||||
.glide/
|
||||
.idea/
|
||||
*.iml
|
||||
|
||||
vendor/
|
||||
glide.lock
|
||||
.DS_Store
|
||||
dist/
|
||||
debug
|
32
.vscode/launch.json
vendored
Normal file
32
.vscode/launch.json
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Debug",
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "debug",
|
||||
"remotePath": "",
|
||||
"port": 2345,
|
||||
"host": "127.0.0.1",
|
||||
"program": "${workspaceRoot}/main.go",
|
||||
"env": {},
|
||||
"args": [],
|
||||
"showLog": true
|
||||
},
|
||||
{
|
||||
"name": "File Debug",
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "debug",
|
||||
"remotePath": "",
|
||||
"port": 2345,
|
||||
"host": "127.0.0.1",
|
||||
"program": "${fileDirname}",
|
||||
"env": {},
|
||||
"args": [],
|
||||
"showLog": true
|
||||
}
|
||||
|
||||
]
|
||||
}
|
11
.vscode/settings.json
vendored
Normal file
11
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
// Place your settings in this file to overwrite default and user settings.
|
||||
{
|
||||
// Specifies Lint tool name.
|
||||
"go.lintTool": "gometalinter",
|
||||
|
||||
// Flags to pass to Lint tool (e.g. ["-min_confidence=.8"])
|
||||
"go.lintFlags": [
|
||||
"--config=${workspaceRoot}/golint.json"
|
||||
]
|
||||
|
||||
}
|
3
glide.yaml
Normal file
3
glide.yaml
Normal file
|
@ -0,0 +1,3 @@
|
|||
package: git.loafle.net/overflow/overflow_grpc_pool
|
||||
import:
|
||||
- package: google.golang.org/grpc
|
44
options.go
Normal file
44
options.go
Normal file
|
@ -0,0 +1,44 @@
|
|||
package overflow_grpc_pool
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultWriteTimeout is default value of Write Timeout
|
||||
DefaultIdleTimeout = 0
|
||||
)
|
||||
|
||||
type (
|
||||
CreateFunc func() (*grpc.ClientConn, interface{}, error)
|
||||
)
|
||||
|
||||
// Options is configuration of the Pool of GRpc client
|
||||
type Options struct {
|
||||
Creators CreateFunc
|
||||
|
||||
IdleTimeout time.Duration
|
||||
MaxIdle int
|
||||
MaxCapacity int
|
||||
}
|
||||
|
||||
// Validate validates the configuration
|
||||
func (o *Options) Validate() *Options {
|
||||
if o.IdleTimeout < 0 {
|
||||
o.IdleTimeout = DefaultIdleTimeout
|
||||
}
|
||||
if o.MaxIdle < 0 {
|
||||
o.MaxIdle = 0
|
||||
}
|
||||
if o.MaxCapacity <= 0 {
|
||||
log.Panicln("Max capacity of Pool must be greater than 0.")
|
||||
}
|
||||
if o.Creators == nil {
|
||||
log.Panicln("Creators of Pool must be specified.")
|
||||
}
|
||||
|
||||
return o
|
||||
}
|
167
pool.go
Normal file
167
pool.go
Normal file
|
@ -0,0 +1,167 @@
|
|||
package overflow_grpc_pool
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrFullPool is the error when the pool is already full
|
||||
ErrPoolFull = errors.New("grpc pool: Pool is reached maximum capacity.")
|
||||
)
|
||||
|
||||
type pooledInstance struct {
|
||||
clientConn *grpc.ClientConn
|
||||
idleTime time.Time
|
||||
instance interface{}
|
||||
inUse bool
|
||||
}
|
||||
|
||||
type Pool interface {
|
||||
Get() (interface{}, error)
|
||||
Put(i interface{})
|
||||
Capacity() int
|
||||
Available() int
|
||||
Destroy()
|
||||
}
|
||||
|
||||
type pool struct {
|
||||
options *Options
|
||||
instances map[interface{}]*pooledInstance
|
||||
instancesCh chan *pooledInstance
|
||||
}
|
||||
|
||||
func New(o *Options) (Pool, error) {
|
||||
var err error
|
||||
p := &pool{
|
||||
options: o.Validate(),
|
||||
instances: make(map[interface{}]*pooledInstance, o.MaxCapacity),
|
||||
instancesCh: make(chan *pooledInstance, o.MaxCapacity),
|
||||
}
|
||||
|
||||
if 0 < o.MaxIdle {
|
||||
for i := 0; i < o.MaxIdle; i++ {
|
||||
err = p.createInstance()
|
||||
if nil != err {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func (p *pool) createInstance() error {
|
||||
maxCapacity := p.options.MaxCapacity
|
||||
currentInstanceCount := len(p.instances)
|
||||
if currentInstanceCount >= maxCapacity {
|
||||
return ErrPoolFull
|
||||
}
|
||||
|
||||
conn, i, err := p.options.Creators()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pi := &pooledInstance{
|
||||
clientConn: conn,
|
||||
idleTime: time.Now(),
|
||||
instance: i,
|
||||
inUse: false,
|
||||
}
|
||||
p.instances[i] = pi
|
||||
p.instancesCh <- pi
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *pool) destroyInstance(i interface{}) {
|
||||
var err error
|
||||
pi, ok := p.instances[i]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
err = pi.clientConn.Close()
|
||||
if nil != err {
|
||||
log.Printf("pool: ClientConn close error: %v", err)
|
||||
}
|
||||
delete(p.instances, i)
|
||||
}
|
||||
|
||||
func (p *pool) get() (*pooledInstance, error) {
|
||||
var pi *pooledInstance
|
||||
var err error
|
||||
|
||||
avail := len(p.instancesCh)
|
||||
if 0 == avail {
|
||||
if err = p.createInstance(); nil != err {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case pi = <-p.instancesCh:
|
||||
// All good
|
||||
default:
|
||||
}
|
||||
idleTimeout := p.options.IdleTimeout
|
||||
if 0 < idleTimeout && pi.idleTime.Add(idleTimeout).Before(time.Now()) {
|
||||
go p.destroyInstance(pi.instance)
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
return pi, nil
|
||||
}
|
||||
|
||||
func (p *pool) Get() (interface{}, error) {
|
||||
var err error
|
||||
var pi *pooledInstance
|
||||
if pi, err = p.get(); nil != err {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pi.inUse = true
|
||||
|
||||
return pi.instance, nil
|
||||
}
|
||||
|
||||
func (p *pool) Put(i interface{}) {
|
||||
pi, ok := p.instances[i]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
pi.idleTime = time.Now()
|
||||
pi.inUse = false
|
||||
|
||||
select {
|
||||
case p.instancesCh <- pi:
|
||||
// All good
|
||||
default:
|
||||
// channel is full
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (p *pool) Capacity() int {
|
||||
return cap(p.instancesCh)
|
||||
}
|
||||
|
||||
func (p *pool) Available() int {
|
||||
return len(p.instancesCh)
|
||||
}
|
||||
|
||||
func (p *pool) Destroy() {
|
||||
close(p.instancesCh)
|
||||
|
||||
for k, _ := range p.instances {
|
||||
p.destroyInstance(k)
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user