-
Notifications
You must be signed in to change notification settings - Fork 153
/
session.go
74 lines (66 loc) · 2.95 KB
/
session.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/*
Copyright 2020 The Qmgo Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package qmgo
import (
"context"
opts "github.com/qiniu/qmgo/options"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/x/mongo/driver"
)
// Session is an struct that represents a MongoDB logical session
type Session struct {
session mongo.Session
}
// StartTransaction starts transaction
//precondition:
//- version of mongoDB server >= v4.0
//- Topology of mongoDB server is not Single
//At the same time, please pay attention to the following
//- make sure all operations in callback use the sessCtx as context parameter
//- Dont forget to call EndSession if session is not used anymore
//- if operations in callback takes more than(include equal) 120s, the operations will not take effect,
//- if operation in callback return qmgo.ErrTransactionRetry,
// the whole transaction will retry, so this transaction must be idempotent
//- if operations in callback return qmgo.ErrTransactionNotSupported,
//- If the ctx parameter already has a Session attached to it, it will be replaced by this session.
func (s *Session) StartTransaction(ctx context.Context, cb func(sessCtx context.Context) (interface{}, error), opts ...*opts.TransactionOptions) (interface{}, error) {
transactionOpts := options.Transaction()
if len(opts) > 0 && opts[0].TransactionOptions != nil {
transactionOpts = opts[0].TransactionOptions
}
result, err := s.session.WithTransaction(ctx, wrapperCustomCb(cb), transactionOpts)
if err != nil {
return nil, err
}
return result, nil
}
// EndSession will abort any existing transactions and close the session.
func (s *Session) EndSession(ctx context.Context) {
s.session.EndSession(ctx)
}
// AbortTransaction aborts the active transaction for this session. This method will return an error if there is no
// active transaction for this session or the transaction has been committed or aborted.
func (s *Session) AbortTransaction(ctx context.Context) error {
return s.session.AbortTransaction(ctx)
}
// wrapperCustomF wrapper caller's callback function to mongo dirver's
func wrapperCustomCb(cb func(ctx context.Context) (interface{}, error)) func(sessCtx mongo.SessionContext) (interface{}, error) {
return func(sessCtx mongo.SessionContext) (interface{}, error) {
result, err := cb(sessCtx)
if err == ErrTransactionRetry {
return nil, mongo.CommandError{Labels: []string{driver.TransientTransactionError}}
}
return result, err
}
}