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:
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)
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:
- 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]
Top comments (0)