func ReleaseLock(resourceID string, requestID string, lockNum int) {
	lockReleaseRequest := LockRequest{ResourceID: resourceID, LockNumber: lockNum, Unlock: true}
	lockRequestsQueue <- lockReleaseRequest
	log.Debugf("Released - Lock Number: %d, requestID: %s, resourceID: %s",
		lockNum, requestID, resourceID)
}
ReleaseLock - Release a held lock for resourceID
Input lockNum should be the same as one returned by RequestLock
package service
import (
	"math/rand"
	"sync"
	"time"
	log "github.com/sirupsen/logrus"
)
type lockWorkers struct {
}
var lockWorker *lockWorkers
type LockRequest struct {
	ResourceID  string
	LockNumber  int
	Unlock      bool
	WaitChannel chan int
}
type LockRequestInfo struct {
	LockNumber  int
	WaitChannel chan int
}
type LockInfo struct {
	LockRequests       chan LockRequestInfo
	CurrentLockNumber  int
	CurrentWaitChannel chan int
	Count              int
}
var lockMutex sync.Mutex
var fifolocks = make(map[string]*LockInfo)
var lockRequestsQueue = make(chan LockRequest, 1000)
func LockRequestHandler() {
	go func() {
		log.Info("Successfully started the lock request handler")
		for {
			select {
			case request := <-lockRequestsQueue:
				lockMutex.Lock()
				lockInfo, ok := fifolocks[request.ResourceID]
				if !ok {
					if request.Unlock {
						log.Warning("There is no lock to be released!")
					} else {
						waitChannels := make(chan LockRequestInfo, 100)
						lockInfo := LockInfo{
							CurrentLockNumber:  request.LockNumber,
							CurrentWaitChannel: request.WaitChannel,
							LockRequests:       waitChannels,
							Count:              1,
						}
						fifolocks[request.ResourceID] = &lockInfo
						request.WaitChannel <- 1
					}
				} else {
					if lockInfo.CurrentLockNumber == request.LockNumber {
						if request.Unlock {
							close(lockInfo.CurrentWaitChannel)
							select {
							case lockRequestInfo := <-lockInfo.LockRequests:
								lockInfo.CurrentLockNumber = lockRequestInfo.LockNumber
								lockInfo.CurrentWaitChannel = lockRequestInfo.WaitChannel
								lockInfo.Count = 1
								lockRequestInfo.WaitChannel <- 1
							default:
								lockInfo.CurrentLockNumber = -1
								lockInfo.Count = 0
							}
						} else {
							log.Warning("Invalid request. There is a lock held with the same request")
						}
					} else {
						if request.Unlock {
							log.Warning("You don't hold the lock")
						} else {
							if len(lockInfo.LockRequests) == 0 && (lockInfo.CurrentLockNumber == -1) {
								lockInfo.CurrentLockNumber = request.LockNumber
								lockInfo.CurrentWaitChannel = request.WaitChannel
								request.WaitChannel <- 1
							} else {
								lockRequestInfo := LockRequestInfo{
									LockNumber:  request.LockNumber,
									WaitChannel: request.WaitChannel,
								}
								lockInfo.LockRequests <- lockRequestInfo
							}
						}
					}
				}
				lockMutex.Unlock()
			}
		}
	}()
}
func CleanupMapEntries(duration time.Duration) {
	ticker := time.NewTicker(duration)
	go func() {
		log.Infof("CleanupMapEntries: Successfully started the cleanup worker. This will wake up every %.2f minutes to clean up stale entries",
			duration.Minutes())
		for {
			select {
			case <-ticker.C:
				lockMutex.Lock()
				now := time.Now()
				log.Debugf("CleanupMapEntries: Current number of entries in lock map: %d", len(fifolocks))
				for resourceID, lockInfo := range fifolocks {
					if time.Since(now) > 20*time.Millisecond {
						log.Debugf("CleanupMapEntries: Held the lock mutex for 20 milliseconds. Releasing it now")
						break
					}
					if lockInfo.CurrentLockNumber == -1 {
						log.Debugf("CleanupMapEntries: Removing stale entry from the lockmap for: %s\n", resourceID)
						delete(fifolocks, resourceID)
					}
				}
				lockMutex.Unlock()
			}
		}
	}()
}
func RequestLock(resourceID string, requestID string) int {
	if requestID != "" {
		log.Debugf("Requesting a lock for %s with requestID: %s at: %v", resourceID, requestID, time.Now())
	}
	lockNum := rand.Intn(10000000-1000000) + 1000000  
	ch := make(chan int, 1)
	lockReq := LockRequest{ResourceID: resourceID, WaitChannel: ch, LockNumber: lockNum, Unlock: false}
	lockRequestsQueue <- lockReq
	<-ch
	log.Debugf("Acquired - Lock Number:%d, requestID: %s, resourceID: %s at: %v",
		lockNum, requestID, resourceID, time.Now())
	return lockNum
}