hhstore / blog

My Tech Blog: about Mojo / Rust / Golang / Python / Kotlin / Flutter / VueJS / Blockchain etc.
https://github.com/hhstore/blog/issues
291 stars 24 forks source link

Annotated: Golang Projects - Digota #130

Open hhstore opened 5 years ago

hhstore commented 5 years ago

Related:

hhstore commented 5 years ago

Digota:

项目架构:

hhstore commented 5 years ago

分布式锁 locker:

实现:

  1. 注意: TryLock(), 返回一个 unlock() 方法, 等待后续执行用.
  2. TryLock() 内部实现, 启动一个 go 例程, 用 select 监听返回.

func (l *locker) TryLock(doc object.Interface, t time.Duration) (func() error, error) {
    key, err := getKey(doc)
    if err != nil {
        return nil, err
    }

    ch := make(chan error)
    conn := l.rp.Get()
    defer conn.Close()

    go func(c redis.Conn) {
        _, err = redis.String(c.Do("SET", key, "NX"))
        select {
        case ch <- err:
        default:
        }
    }(conn)

    select {
    case err = <-ch:
        if err != nil {
            return nil, err
        }
        return func() error { return l.unlock(key) }, nil
    case <-time.After(t):
        return nil, ErrTimeout
    }
}

func (l *locker) unlock(key string) error {
    conn := l.rp.Get()
    _, err := conn.Do("DEL", key)
    conn.Close()
    return err
}

应用:

  1. product 服务, 对 get 操作, db 查询之前加锁.

// Get
func (s *productService) Get(ctx context.Context, req *productpb.GetRequest) (*productpb.Product, error) {

    if err := validation.Validate(req); err != nil {
        return nil, err
    }

    p := &product{
        Product: productpb.Product{
            Id: req.Id,
        },
    }

    unlock, err := locker.Handler().TryLock(p, time.Second)
    if err != nil {
        return nil, err
    }
    defer unlock()

    if err := storage.Handler().One(p); err != nil {
        return nil, err
    }

    // get products skus

    skus, err := sku.Service().ProductData(ctx, &sku.ProductDataReq{Id: p.GetId()})

    if err != nil {
        return nil, err
    }

    p.Skus = skus

    return &p.Product, nil

}
hhstore commented 5 years ago

mongodb orm:

package mongo

import (
        ....
    "github.com/digota/digota/storage/object"
        ....
    "gopkg.in/mgo.v2"
    "gopkg.in/mgo.v2/bson"
)

// mongodb 对象:
type handler struct {
    client   *mgo.Session  // db 对象
    dailInfo *mgo.DialInfo // db 连接
    database string
}

// Insert
func (h *handler) Insert(obj object.Interface) error {

    s := h.client.New()

    defer s.Close()

    if v, ok := obj.(object.IdSetter); ok {
        v.SetId(uuid.NewV4().String())
    }

    if v, ok := obj.(object.TimeTracker); ok {
        v.SetCreated(time.Now().Unix())
        v.SetUpdated(time.Now().Unix())
    }

    if err := s.DB(h.database).C(obj.GetNamespace()).Insert(obj); err != nil {
        return status.Error(codes.Internal, err.Error())
    }

    return nil

}