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 }