Project has been created
This commit is contained in:
commit
1e3c1c1446
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/commons_go/grpc_pool
|
||||||
|
import:
|
||||||
|
- package: google.golang.org/grpc
|
171
pool.go
Normal file
171
pool.go
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
package overflow_grpc_pool
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"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 {
|
||||||
|
ctx context.Context
|
||||||
|
handler PoolHandler
|
||||||
|
instances map[interface{}]*pooledInstance
|
||||||
|
instancesCh chan *pooledInstance
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(ctx context.Context, handler PoolHandler) (Pool, error) {
|
||||||
|
var err error
|
||||||
|
p := &pool{
|
||||||
|
ctx: ctx,
|
||||||
|
handler: handler,
|
||||||
|
instances: make(map[interface{}]*pooledInstance, handler.GetMaxCapacity()),
|
||||||
|
instancesCh: make(chan *pooledInstance, handler.GetMaxCapacity()),
|
||||||
|
}
|
||||||
|
|
||||||
|
if 0 < handler.GetMaxIdle() {
|
||||||
|
for i := 0; i < handler.GetMaxIdle(); i++ {
|
||||||
|
err = p.createInstance()
|
||||||
|
if nil != err {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pool) createInstance() error {
|
||||||
|
maxCapacity := p.handler.GetMaxCapacity()
|
||||||
|
currentInstanceCount := len(p.instances)
|
||||||
|
if currentInstanceCount >= maxCapacity {
|
||||||
|
return ErrPoolFull
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, i, err := p.handler.OnCreate()
|
||||||
|
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{}) error {
|
||||||
|
var err error
|
||||||
|
pi, ok := p.instances[i]
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err = pi.clientConn.Close()
|
||||||
|
if nil != err {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
delete(p.instances, i)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
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.handler.GetIdleTimeout()
|
||||||
|
if 1 < len(p.instancesCh) && 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
23
pool_handler.go
Normal file
23
pool_handler.go
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
package overflow_grpc_pool
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DefaultWriteTimeout is default value of Write Timeout
|
||||||
|
DefaultIdleTimeout = 0
|
||||||
|
DefaultMaxIdle = 0
|
||||||
|
DefaultMaxCapacity = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
type PoolHandler interface {
|
||||||
|
GetIdleTimeout() time.Duration
|
||||||
|
GetMaxIdle() int
|
||||||
|
GetMaxCapacity() int
|
||||||
|
|
||||||
|
OnCreate() (*grpc.ClientConn, interface{}, error)
|
||||||
|
Validate()
|
||||||
|
}
|
41
pool_handlers.go
Normal file
41
pool_handlers.go
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
package overflow_grpc_pool
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Options is configuration of the Pool of GRpc client
|
||||||
|
type PoolHandlers struct {
|
||||||
|
IdleTimeout time.Duration
|
||||||
|
MaxIdle int
|
||||||
|
MaxCapacity int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *PoolHandlers) GetIdleTimeout() time.Duration {
|
||||||
|
return h.IdleTimeout
|
||||||
|
}
|
||||||
|
func (h *PoolHandlers) GetMaxIdle() int {
|
||||||
|
return h.MaxIdle
|
||||||
|
}
|
||||||
|
func (h *PoolHandlers) GetMaxCapacity() int {
|
||||||
|
return h.MaxCapacity
|
||||||
|
}
|
||||||
|
func (h *PoolHandlers) OnCreate() (*grpc.ClientConn, interface{}, error) {
|
||||||
|
return nil, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate validates the configuration
|
||||||
|
func (o *PoolHandlers) Validate() {
|
||||||
|
if o.IdleTimeout < 0 {
|
||||||
|
o.IdleTimeout = DefaultIdleTimeout
|
||||||
|
}
|
||||||
|
if o.MaxIdle < 0 {
|
||||||
|
o.MaxIdle = DefaultMaxIdle
|
||||||
|
}
|
||||||
|
if o.MaxCapacity <= 0 {
|
||||||
|
o.MaxCapacity = DefaultMaxCapacity
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user