Ravi
Ravi

Reputation: 31

How to write a functionality on web based service that runs when the time duration will expire and restart the timer again in golang

I wanted to write this functionality in server side code. Is there effective way to write a functionality that runs in background for certain time duration and when time duration expires it triggers the event. After that it restart the timer to trigger the event for the next time, again and again.

I wanted to do this asynchronously, like Timer starts that runs in the background and when it expired call the function to execute. after the function finishes it's execution it again trigger a event/ function asynchronously that restart the timer without waiting anywhere in the code.

Time duration will be calculated dynamically every time.

I have tried using below approach but it waiting for Channels and I have to run for loop that also block the code.

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "os"
    "strconv"
    "strings"
    "time"
)

const INTERVAL_PERIOD time.Duration = 24 * time.Hour

var HOUR_TO_TICK int
var MINUTE_TO_TICK int
var SECOND_TO_TICK int

type jobTicker struct {
    t *time.Timer
}

func setConfig(appconfs map[string]string) bool {

    timeOfEventTrigger := appconfs["Task_Trigger_Time"]
    clockTime := strings.Split(timeOfEventTrigger, ":")

    fmt.Println("fixed clock time to trigger event  ", clockTime)

    HOUR_TO_TICK, _ = strconv.Atoi(clockTime[0])
    MINUTE_TO_TICK, _ = strconv.Atoi(clockTime[1])
    SECOND_TO_TICK, _ = strconv.Atoi(clockTime[2])

    return true

}

func readConfigFromJson(configPath string) bool {
    fmt.Printf("Loading Configurations from %s\n", configPath)
    configMap := map[string]string{}
    configfile, err := os.Open(configPath)
    if err != nil {
        fmt.Printf("Unable to the load the config: %v\n", err)
        return false
    }
    byteValue, err := ioutil.ReadAll(configfile)
    if err != nil {
        fmt.Printf("Unable to decode the config: %v\n", err)
        return false
    }
    err = json.Unmarshal(byteValue, &configMap)
    if err != nil {
        fmt.Printf("Unable to Unmarshal to JSON: %v\n", err)
        return false
    }

    defer configfile.Close()
    return setConfig(configMap)
}

func getNextTickDuration() time.Duration {

    now := time.Now()
    nextTick := time.Date(now.Year(), now.Month(), now.Day(), HOUR_TO_TICK, MINUTE_TO_TICK, SECOND_TO_TICK, 0, time.Local)

    if nextTick.Before(now) {
        nextTick = nextTick.Add(INTERVAL_PERIOD)
    }
    fmt.Println("Current time is -> ", now)
    fmt.Println(" next trigger at this date and time - ", nextTick)
    waitDuration := nextTick.Sub(time.Now())
    fmt.Println(" clock is waiting for duration -> ", waitDuration)
    return waitDuration

}

func NewJobTicker() jobTicker {
    fmt.Println("genrate new job ticker here")
    return jobTicker{time.NewTimer(getNextTickDuration())}
}

func (jt jobTicker) updateJobTicker() {
    fmt.Println("update job ticker here")
    jt.t.Reset(getNextTickDuration())
}

func startTmer () {
    jt := NewJobTicker()

    for {
        <-jt.t.C
        fmt.Println(time.Now(), "- just ticked")
        // do our logic 
        jt.updateJobTicker()
    }
}

here is the json file that is being read for the time to execute event.

// config.json
{
    "Task_Trigger_Time": "12:30:00"
}

Upvotes: 1

Views: 91

Answers (2)

whitespace
whitespace

Reputation: 821

have added a few changes to original code. This takes care of panic, incase it happens while reading the duration, and uses time.Sleep instead of time.AfterFunc.

//start the timer again
func performOutdatedOperationForStore() {

// do somthing 

// start the timer again
   timeDurationToWait,err := getNextTickDuration()
   if err!=nil{
     //log error
   }

    go StartTimeDuration(timeDurationToWait)

}

func StartTimeDuration(timeDurationToWait string) {

    // start timer
    time.Sleep(timeDurationToWait)
    performOutdatedOperationForStore()
    //time.AfterFunc(timeDurationToWait, func() { performOutdatedOperationForStore() }): this calls performOutdatedOperationForStore() in a new go routine, which is also ok, but not nesseccary.

}

Upvotes: 1

Ravi
Ravi

Reputation: 31

Hi I have done it this way. Please suggest a better way if Possible in brief. I am a complete newbie it will help me a lot...

//start the timer again
func performOutdatedOperationForStore() {

// do somthing 

// start the timer again
    go StartTimeDuration()

}
    func StartTimeDuration() {
    
        // start timer
        timeDurationToWait := getNextTickDuration()
        // gvalidObjectTime := config.ConfigurationObject.ObjectLifeTimeTTL
        time.AfterFunc(timeDurationToWait, func() { performOutdatedOperationForStore() })
    
    }

Upvotes: -1

Related Questions