I'm aiming to do transaction management in the code below. If there is an error in one of the strategies, I am trying to rollback. While testing the code, I noticed that if the rollback or commit command works once, it gives error = transaction has already been committed or rolled back the second time. How can I resolve this error?
func (d *DistributeService) Distribute(vehicleNumberPlate string, request model.DistributeRequest) (*model.DistributeResponse, error) {
var response model.DistributeResponse
response.Vehicle = vehicleNumberPlate
var routeList []model.RouteResponse
tx := d.repo.BeginTransaction()
for _, routes := range request.RouteRequest {
var routeResponse model.RouteResponse
strategy, isStrategyExists := d.strategies[routes.DeliveryPoint]
if isStrategyExists {
resp, err := strategy.Distribute(routes.Deliveries, vehicleNumberPlate, tx)
if err != nil {
tx.Rollback()
logrus.Errorf("Error while distributing: %v", err)
return nil, err
}
routeResponse.DeliveryPoint = routes.DeliveryPoint
routeResponse.Deliveries = *resp
routeList = append(routeList, routeResponse)
} else {
logrus.Errorf("Invalid delivery point: %v", routes.DeliveryPoint)
return nil, errors.New("invalid delivery point")
}
}
response.RouteResponse = routeList
err := d.checkSackPackagesAreUnloaded()
tx.Commit()
if err != nil {
return nil, err
}
return &response, nil
}
You're probably using the same transaction object in each call. If it was closed once - for whatever reason - you need to create a new transaction object.
Why do I say you are probably using the same transaction object you ask?
Because you're basically passing a pointer to d *DistributeService
.
And then use tx := d.repo.BeginTransaction()
. We can't tell what that code does, but I'm pretty sure you're returning the same transaction object here for subsequent runs.
The solution is to create a new transaction object every time this method is called, f.e. with tx := db.Begin()
as described in the docs.