Skip to content

Instantly share code, notes, and snippets.

@podanypepa
Last active February 27, 2021 17:52
Show Gist options
  • Select an option

  • Save podanypepa/192889594733a43dad9d5fbbea740fb2 to your computer and use it in GitHub Desktop.

Select an option

Save podanypepa/192889594733a43dad9d5fbbea740fb2 to your computer and use it in GitHub Desktop.
package main
import (
"context"
"fmt"
"log"
"time"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"gopkg.in/mgo.v2/bson"
)
type LockObject struct {
InTransaction bool `json:"inTransaction" bson:"inTransaction"`
Name string `json:"name" bson:"name"`
}
var (
url = "mongodb+srv://mongodb:CONNECTION_STRING..."
dbiName = "locker"
colname = "locker"
MongoClient *mongo.Client
coll *mongo.Collection
)
func main() {
// you can specify lock name for more then one lock in collection
lockName := "globalLock"
fmt.Println("start")
// blocked until getting lock
if Lock(lockName) {
// after getting lock
fmt.Println("heja! locked by me!")
}
fmt.Println("and continue...")
// uncomment for unlock
// if you run with commented Unlock() will be blocked next app run
// Unlock(lockName)
_ = MongoClient.Disconnect(context.TODO())
}
func Lock(lockName string) (locked bool) {
var (
filter = bson.M{
"inTransaction": bson.M{
"$exists": true,
},
"name": lockName,
}
locker = bson.M{
"$set": LockObject{
InTransaction: true,
Name: lockName,
},
}
upsert = true
opt = options.UpdateOptions{
Upsert: &upsert,
}
)
if MongoClient == nil {
var err error
if MongoClient, err = mongo.Connect(context.TODO(),options.Client().ApplyURI(url)); err != nil {
log.Fatal(err)
}
coll = MongoClient.Database(dbiName).Collection(colname)
fmt.Println("mongo connected")
}
for !locked {
res, err := coll.UpdateOne(context.TODO(), filter, locker, &opt)
if err != nil {
return false
}
locked = res.UpsertedCount == 1
if !locked {
fmt.Println("locked by someone else")
time.Sleep(1 * time.Second)
}
}
return locked
}
func Unlock(lockName string) error {
var (
filter = bson.M{
"inTransaction": bson.M{
"$exists": true,
},
"name": lockName,
}
)
res, err := coll.DeleteOne(context.TODO(), filter)
if err != nil {
return err
}
if res.DeletedCount != 1 {
return fmt.Errorf("unlcck error")
}
return nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment