Solving simple time based problems with go lang.
Tags: go, programming, backenddevelopment
Published: 2024-05-13 11:25:33


so interestingly i was assigned a task i really enjoyed, this had to do with repeatedly looping over a set of documents in the db, making some transactions and finally updating documents based on certain conditions.
The first idea was to use a Cron Job(well obviously) everyone knows what a cron job does, but interestingly the problem was to be solved using Go Lang which is one of our stacks on my current team.

I shared the problem with the backend team and we discussed different methods to approach the problem and at the end of the day it boiled down to setting up a cron job that runs repeatedly at “x time” or using the Go timer package.

I used the go timer package and i used it mainly for two reasons:

1. **Ease of use:** it was already pre-installed, easy to use and provides a plethora of methods and properties that could be used to solve basically all the problems presented on a low level (it gives total control)

2. **Less complexity:** I was already using go lang, there was no real need to install a separate package to over engineer a somewhat simple problem.

Here’s a simple snippet of how to solve the same type of problem:


1. We define our timed funtion
for this example we'll be using the go MongoDB and mux router 

```
// assuming we want the function to run at 12am daily
func initTimer(conn *db.MongoDB, router *mux.Router) {
	currentTime := time.Now()

	// Calculate the duration until 12 AM
	desiredTime := time.Date(currentTime.Year(), currentTime.Month(), currentTime.Day(), 0, 0, 0, 0, currentTime.Location())
	if desiredTime.Before(currentTime) {
		// If 12AM has already passed today, schedule it for 12AM tomorrow
		desiredTime = desiredTime.Add(24 * time.Hour)
	}

	// Calculate the duration until the 12AM
	duration := desiredTime.Sub(currentTime)

	// Wait until it's time to execute the function
	<-time.After(duration)
	go ourTransaction(conn, router)
}

func ourTransaction(conn *db.MongoDB, router *mux.Router) {
   entity := pkg.InitTrxn(conn, router) //init package
    

    //initial transaction to counter build during updates (optional)
    go entity.RunTrxn()

	// re-run this function every 24hrs by setting up a new ticker using the "time.NewTicker" function
	var ticker *time.Ticker = time.NewTicker(24 * time.Hour)

    //repeat actions at intervals using the "ticker.C" field
	for tickTime := range ticker.C {
		go entity.RunTrxn() // a resource intensive function
		log.Println("i'm running at time:", tickTime)
	}
}
```

- We initialize the timed functions in our main.go package

```
func main(){
// initialize 
	go initTimer(dbConn, router) // run on a separate thread 
}
```

- In my case the the transaction needed me to make an update base on last action time (..actally i just want to show more stuff done with the go timer package 😏).

```
package packageName

func (t trxnStruct) RunTrxn() {
       items, err := t.GetAllItems()
       if err != nil{
          log.Panicf("Error at getting items %s", err)
          }

       for _, item := range items {

       // get time difference between last transaction time  and current time using the "time.since" function
         timeDifferenceSinceLastTrxn = time.Since(item.LastTransactionTime)

		inActiveDays := int(timeDifferenceSinceLastTrxn.Hours() / 24) //convert to days
		item.InActiveDays = inActiveDays
         maxdaysofInactivity := 10 

        if item.InActiveDays > maxdaysofInactivity{
           item.Status = constants.INACTIVE	
          }

        t.UpdateItem(item.ID, item) // repo funtion to update DB Record

      }
   return
}
```

In conclusion, the go timer package is a robust and yet easy to use package with a lot of useful tools to help solve your time based based problems. you can find more info from the docs [https://pkg.go.dev/time]