You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
cronsun/client.go

150 lines
3.4 KiB

package cronsun
import (
"context"
"fmt"
"strings"
"time"
client "github.com/coreos/etcd/clientv3"
"github.com/shunfei/cronsun/conf"
)
var (
DefalutClient *Client
)
type Client struct {
*client.Client
reqTimeout time.Duration
}
func NewClient(cfg *conf.Conf) (c *Client, err error) {
cli, err := client.New(cfg.Etcd.Copy())
if err != nil {
return
}
c = &Client{
Client: cli,
reqTimeout: time.Duration(cfg.ReqTimeout) * time.Second,
}
return
}
func (c *Client) Put(key, val string, opts ...client.OpOption) (*client.PutResponse, error) {
ctx, cancel := NewEtcdTimeoutContext(c)
defer cancel()
return c.Client.Put(ctx, key, val, opts...)
}
func (c *Client) PutWithModRev(key, val string, rev int64) (*client.PutResponse, error) {
8 years ago
if rev == 0 {
return c.Put(key, val)
}
ctx, cancel := NewEtcdTimeoutContext(c)
8 years ago
tresp, err := DefalutClient.Txn(ctx).
If(client.Compare(client.ModRevision(key), "=", rev)).
8 years ago
Then(client.OpPut(key, val)).
Commit()
cancel()
if err != nil {
return nil, err
}
if !tresp.Succeeded {
return nil, ErrValueMayChanged
}
resp := client.PutResponse(*tresp.Responses[0].GetResponsePut())
return &resp, nil
}
func (c *Client) Get(key string, opts ...client.OpOption) (*client.GetResponse, error) {
ctx, cancel := NewEtcdTimeoutContext(c)
defer cancel()
return c.Client.Get(ctx, key, opts...)
}
func (c *Client) Delete(key string, opts ...client.OpOption) (*client.DeleteResponse, error) {
ctx, cancel := NewEtcdTimeoutContext(c)
defer cancel()
return c.Client.Delete(ctx, key, opts...)
}
func (c *Client) Watch(key string, opts ...client.OpOption) client.WatchChan {
return c.Client.Watch(context.Background(), key, opts...)
}
func (c *Client) Grant(ttl int64) (*client.LeaseGrantResponse, error) {
ctx, cancel := NewEtcdTimeoutContext(c)
defer cancel()
return c.Client.Grant(ctx, ttl)
}
func (c *Client) Revoke(id client.LeaseID) (*client.LeaseRevokeResponse, error) {
ctx, cancel := context.WithTimeout(context.Background(), c.reqTimeout)
defer cancel()
return c.Client.Revoke(ctx, id)
}
func (c *Client) KeepAliveOnce(id client.LeaseID) (*client.LeaseKeepAliveResponse, error) {
ctx, cancel := NewEtcdTimeoutContext(c)
defer cancel()
return c.Client.KeepAliveOnce(ctx, id)
}
func (c *Client) GetLock(key string, id client.LeaseID) (bool, error) {
key = conf.Config.Lock + key
ctx, cancel := NewEtcdTimeoutContext(c)
resp, err := DefalutClient.Txn(ctx).
If(client.Compare(client.CreateRevision(key), "=", 0)).
Then(client.OpPut(key, "", client.WithLease(id))).
Commit()
cancel()
if err != nil {
return false, err
}
return resp.Succeeded, nil
}
func (c *Client) DelLock(key string) error {
_, err := c.Delete(conf.Config.Lock + key)
return err
}
func IsValidAsKeyPath(s string) bool {
return strings.IndexAny(s, "/\\") == -1
}
// etcdTimeoutContext return better error info
type etcdTimeoutContext struct {
context.Context
etcdEndpoints []string
}
func (c *etcdTimeoutContext) Err() error {
err := c.Context.Err()
if err == context.DeadlineExceeded {
err = fmt.Errorf("%s: etcd(%v) maybe lost",
err, c.etcdEndpoints)
}
return err
}
// NewEtcdTimeoutContext return a new etcdTimeoutContext
func NewEtcdTimeoutContext(c *Client) (context.Context, context.CancelFunc) {
ctx, cancel := context.WithTimeout(context.Background(), c.reqTimeout)
etcdCtx := &etcdTimeoutContext{}
etcdCtx.Context = ctx
etcdCtx.etcdEndpoints = c.Endpoints()
return etcdCtx, cancel
}