github.com/lingyao2333/mo-zero@v1.4.1/core/stores/mongo/collection.go (about)

     1  package mongo
     2  
     3  import (
     4  	"encoding/json"
     5  	"time"
     6  
     7  	"github.com/globalsign/mgo"
     8  	"github.com/lingyao2333/mo-zero/core/breaker"
     9  	"github.com/lingyao2333/mo-zero/core/logx"
    10  	"github.com/lingyao2333/mo-zero/core/stores/mongo/internal"
    11  	"github.com/lingyao2333/mo-zero/core/timex"
    12  )
    13  
    14  const defaultSlowThreshold = time.Millisecond * 500
    15  
    16  // ErrNotFound is an alias of mgo.ErrNotFound.
    17  var ErrNotFound = mgo.ErrNotFound
    18  
    19  type (
    20  	// Collection interface represents a mongo connection.
    21  	Collection interface {
    22  		Find(query interface{}) Query
    23  		FindId(id interface{}) Query
    24  		Insert(docs ...interface{}) error
    25  		Pipe(pipeline interface{}) Pipe
    26  		Remove(selector interface{}) error
    27  		RemoveAll(selector interface{}) (*mgo.ChangeInfo, error)
    28  		RemoveId(id interface{}) error
    29  		Update(selector, update interface{}) error
    30  		UpdateId(id, update interface{}) error
    31  		Upsert(selector, update interface{}) (*mgo.ChangeInfo, error)
    32  	}
    33  
    34  	decoratedCollection struct {
    35  		name       string
    36  		collection internal.MgoCollection
    37  		brk        breaker.Breaker
    38  	}
    39  
    40  	keepablePromise struct {
    41  		promise breaker.Promise
    42  		log     func(error)
    43  	}
    44  )
    45  
    46  func newCollection(collection *mgo.Collection, brk breaker.Breaker) Collection {
    47  	return &decoratedCollection{
    48  		name:       collection.FullName,
    49  		collection: collection,
    50  		brk:        brk,
    51  	}
    52  }
    53  
    54  func (c *decoratedCollection) Find(query interface{}) Query {
    55  	promise, err := c.brk.Allow()
    56  	if err != nil {
    57  		return rejectedQuery{}
    58  	}
    59  
    60  	startTime := timex.Now()
    61  	return promisedQuery{
    62  		Query: c.collection.Find(query),
    63  		promise: keepablePromise{
    64  			promise: promise,
    65  			log: func(err error) {
    66  				duration := timex.Since(startTime)
    67  				c.logDuration("find", duration, err, query)
    68  			},
    69  		},
    70  	}
    71  }
    72  
    73  func (c *decoratedCollection) FindId(id interface{}) Query {
    74  	promise, err := c.brk.Allow()
    75  	if err != nil {
    76  		return rejectedQuery{}
    77  	}
    78  
    79  	startTime := timex.Now()
    80  	return promisedQuery{
    81  		Query: c.collection.FindId(id),
    82  		promise: keepablePromise{
    83  			promise: promise,
    84  			log: func(err error) {
    85  				duration := timex.Since(startTime)
    86  				c.logDuration("findId", duration, err, id)
    87  			},
    88  		},
    89  	}
    90  }
    91  
    92  func (c *decoratedCollection) Insert(docs ...interface{}) (err error) {
    93  	return c.brk.DoWithAcceptable(func() error {
    94  		startTime := timex.Now()
    95  		defer func() {
    96  			duration := timex.Since(startTime)
    97  			c.logDuration("insert", duration, err, docs...)
    98  		}()
    99  
   100  		return c.collection.Insert(docs...)
   101  	}, acceptable)
   102  }
   103  
   104  func (c *decoratedCollection) Pipe(pipeline interface{}) Pipe {
   105  	promise, err := c.brk.Allow()
   106  	if err != nil {
   107  		return rejectedPipe{}
   108  	}
   109  
   110  	startTime := timex.Now()
   111  	return promisedPipe{
   112  		Pipe: c.collection.Pipe(pipeline),
   113  		promise: keepablePromise{
   114  			promise: promise,
   115  			log: func(err error) {
   116  				duration := timex.Since(startTime)
   117  				c.logDuration("pipe", duration, err, pipeline)
   118  			},
   119  		},
   120  	}
   121  }
   122  
   123  func (c *decoratedCollection) Remove(selector interface{}) (err error) {
   124  	return c.brk.DoWithAcceptable(func() error {
   125  		startTime := timex.Now()
   126  		defer func() {
   127  			duration := timex.Since(startTime)
   128  			c.logDuration("remove", duration, err, selector)
   129  		}()
   130  
   131  		return c.collection.Remove(selector)
   132  	}, acceptable)
   133  }
   134  
   135  func (c *decoratedCollection) RemoveAll(selector interface{}) (info *mgo.ChangeInfo, err error) {
   136  	err = c.brk.DoWithAcceptable(func() error {
   137  		startTime := timex.Now()
   138  		defer func() {
   139  			duration := timex.Since(startTime)
   140  			c.logDuration("removeAll", duration, err, selector)
   141  		}()
   142  
   143  		info, err = c.collection.RemoveAll(selector)
   144  		return err
   145  	}, acceptable)
   146  
   147  	return
   148  }
   149  
   150  func (c *decoratedCollection) RemoveId(id interface{}) (err error) {
   151  	return c.brk.DoWithAcceptable(func() error {
   152  		startTime := timex.Now()
   153  		defer func() {
   154  			duration := timex.Since(startTime)
   155  			c.logDuration("removeId", duration, err, id)
   156  		}()
   157  
   158  		return c.collection.RemoveId(id)
   159  	}, acceptable)
   160  }
   161  
   162  func (c *decoratedCollection) Update(selector, update interface{}) (err error) {
   163  	return c.brk.DoWithAcceptable(func() error {
   164  		startTime := timex.Now()
   165  		defer func() {
   166  			duration := timex.Since(startTime)
   167  			c.logDuration("update", duration, err, selector, update)
   168  		}()
   169  
   170  		return c.collection.Update(selector, update)
   171  	}, acceptable)
   172  }
   173  
   174  func (c *decoratedCollection) UpdateId(id, update interface{}) (err error) {
   175  	return c.brk.DoWithAcceptable(func() error {
   176  		startTime := timex.Now()
   177  		defer func() {
   178  			duration := timex.Since(startTime)
   179  			c.logDuration("updateId", duration, err, id, update)
   180  		}()
   181  
   182  		return c.collection.UpdateId(id, update)
   183  	}, acceptable)
   184  }
   185  
   186  func (c *decoratedCollection) Upsert(selector, update interface{}) (info *mgo.ChangeInfo, err error) {
   187  	err = c.brk.DoWithAcceptable(func() error {
   188  		startTime := timex.Now()
   189  		defer func() {
   190  			duration := timex.Since(startTime)
   191  			c.logDuration("upsert", duration, err, selector, update)
   192  		}()
   193  
   194  		info, err = c.collection.Upsert(selector, update)
   195  		return err
   196  	}, acceptable)
   197  
   198  	return
   199  }
   200  
   201  func (c *decoratedCollection) logDuration(method string, duration time.Duration, err error, docs ...interface{}) {
   202  	content, e := json.Marshal(docs)
   203  	if e != nil {
   204  		logx.Error(err)
   205  	} else if err != nil {
   206  		if duration > slowThreshold.Load() {
   207  			logx.WithDuration(duration).Slowf("[MONGO] mongo(%s) - slowcall - %s - fail(%s) - %s",
   208  				c.name, method, err.Error(), string(content))
   209  		} else {
   210  			logx.WithDuration(duration).Infof("mongo(%s) - %s - fail(%s) - %s",
   211  				c.name, method, err.Error(), string(content))
   212  		}
   213  	} else {
   214  		if duration > slowThreshold.Load() {
   215  			logx.WithDuration(duration).Slowf("[MONGO] mongo(%s) - slowcall - %s - ok - %s",
   216  				c.name, method, string(content))
   217  		} else {
   218  			logx.WithDuration(duration).Infof("mongo(%s) - %s - ok - %s", c.name, method, string(content))
   219  		}
   220  	}
   221  }
   222  
   223  func (p keepablePromise) accept(err error) error {
   224  	p.promise.Accept()
   225  	p.log(err)
   226  	return err
   227  }
   228  
   229  func (p keepablePromise) keep(err error) error {
   230  	if acceptable(err) {
   231  		p.promise.Accept()
   232  	} else {
   233  		p.promise.Reject(err.Error())
   234  	}
   235  
   236  	p.log(err)
   237  	return err
   238  }
   239  
   240  func acceptable(err error) bool {
   241  	return err == nil || err == mgo.ErrNotFound
   242  }