DEV Community

Yusuf Turhan Papurcu for Golang

Posted on

2 2

⌛️ Manage time specified operations with Go in easy way.

In programming we need specifying time for our code. Sometimes we wait until our crush end her relationship. Sometimes we wait until summer to change our job.

Let's Start!

For doing thing with specified time I will show the basics in Go. In the first part we will look 2 simple code part. After we will discuss about how can we improve them and make it usable even production environment.

Part 1 — Basics Of Time Specifying in Go

For time specifying we will use 2 basic technique. First one is for blocking current goroutine until specified time.

func main() {
// This will block for 5 seconds and then return the current time
theTime := <-time.After(time.Second * 5)
fmt.Println(theTime.Format("2006-01-02 15:04:05"))
}
view raw example-1.go hosted with ❤ by GitHub

In this example goroutine blocked for 5 second at 3rd line and continues after this. If you want waiting more time and doing more readable. You can use time.Until(). Here a basic example for this.

func main() {
// Set when we want to continue
until, _ := time.Parse(time.RFC3339, "2023-01-01T00:00:01+02:00")
// Wait until it
<-time.After(time.Until(until))
}
view raw example-2.go hosted with ❤ by GitHub

Second technique is blocking goroutine forever and make it cron engine. For doing this we have an excellent function called time.Tick(). This method takes duration and returns channel that triggers at every duration loop.

func main() {
// This will print the time every 5 seconds
for theTime := range time.Tick(time.Second * 5) {
fmt.Println(theTime.Format("2006-01-02 15:04:05"))
}
}
view raw example-3.go hosted with ❤ by GitHub

If you don’t care about current time and just want to execute code continuously you can use this one. Also this way is more manageable and allow control flow with context or specific trigger channels.

func main() {
for {
select {
// This usage will ignore actual time
// Just runs in every 5 second
case <-time.Tick(time.Second * 5):
fmt.Println("I'm a bot that saying 'You are amazing' in every 5 second")
}
}
}
view raw example-4.go hosted with ❤ by GitHub

Part 2 — Let’s Improve Them With Context Package

Context package is so useful. Because Context gives you a power of cancellation. You can cancel functions with it. If you are doing things with time, context is like Thor’s Mjölnir for you.

Key part of using context is based on for { select{…} } loop. Also you must use async for be able to use context. Because If your code flow don’t run, you can’t cancel the context.

Let’s do some examples. First we will implement a basic wait function with context. If context cancel called before timer end, function will exit without wait to timer end. In that case our program just wait 5 second instead of 5 minutes. That can annoy your goroutine :)

func main() {
ctx, cancel := context.WithCancel(context.Background())
go func() {
fmt.Println("Let's wait 5 minute")
WaitUntilWithContext(ctx, time.Minute*5)
fmt.Println("Hey!! Why we exited after 5 second !?!??!")
}()
time.Sleep(5 * time.Second)
cancel()
time.Sleep(10 * time.Second)
}
func WaitUntilWithContext(ctx context.Context, diff time.Duration) {
timer := time.NewTimer(diff)
defer timer.Stop()
select {
case <-timer.C:
return
case <-ctx.Done():
return
}
}
view raw context-1.go hosted with ❤ by GitHub

For key point. We split our waiting routine and main routine. We must do that because if we didn’t do that we can’t call cancel function asynchronously.

Creating cron engine with context is basic than previous example. Just add context.Done() to the select statement.

func main() {
ctx, cancel := context.WithCancel(context.Background())
go func() {
for {
select {
// This usage will ignore actual time
// Just runs in every 5 second
case <-ctx.Done():
return
case <-time.Tick(time.Second * 5):
fmt.Println("I'm a bot that saying 'You are amazing' in every 5 second")
}
}
}()
time.Sleep(11 * time.Second)
cancel()
time.Sleep(5 * time.Second)
}
view raw context-2.go hosted with ❤ by GitHub

For a final example I want to add more complex, beautiful and useful cron engine example from here. I won’t add code to article. You can use link for this. Also this repository is a great implementation and my inspiration for writing this article.

I would like to hear all feedback’s about this article. Please feel free to give feedback. I want to hear all of good and bad feedbacks :)

I’m planning to expand this article some. If you have an idea what can I talk about at the feature of this article, I want to hear it.

Inspired Articles

Good Repositories

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more