CRON JOB in GOLANG - go

I AM USING IN CRON PKG https://github.com/jasonlvhit/gocron/blob/master/gocron.go
import (
"fmt"
"time"
"github.com/claudiu/gocron"
)
func task() {
fmt.Println("I am runnning task.", time.Now())
}
func vijay() {
fmt.Println("I am runnning vijay.", time.Now())
}
func main() {
go test()
gocron.Start()
s := gocron.NewScheduler()
gocron.Every(5).Seconds().Do(task)
gocron.Every(10).Seconds().Do(vijay)
<-s.Start()
}
func test() {
time.Sleep(20 * time.Second)
gocron.Clear()
fmt.Println("All task removed")
}
My problem is after removing all job, my program is still executing
i want to break the exection after removing all jobs
please help me out ,i am not able to find out how to do it ,
i tried to change the PKG source code also but not able to find out the way to do it
thank you all

First, you're creating a new scheduler, and waiting on it, but using the default scheduler to run your jobs.
Next, you're blocking on the channel returned by the Start() method. Close that channel to unblock the receive operation. This will also exit the main loop in the cron program if you aren't immediately exiting from main.
func main() {
ch := gocron.Start()
go test(ch)
gocron.Every(5).Seconds().Do(task)
gocron.Every(10).Seconds().Do(vijay)
<-ch
}
func test(stop chan bool) {
time.Sleep(20 * time.Second)
gocron.Clear()
fmt.Println("All task removed")
close(stop)
}
which effectively is the same as
func main() {
gocron.Start()
gocron.Every(5).Seconds().Do(task)
gocron.Every(10).Seconds().Do(vijay)
time.Sleep(20 * time.Second)
gocron.Clear()
fmt.Println("All task removed")
}
If you're exiting immediately, it doesn't really matter if you call Clear() first and then stop the scheduler, you can simply exit the program.

JimB rights. But I don't know why do you use gocron methods and the s methods. This example works fine:
package main
import (
"fmt"
"time"
"github.com/claudiu/gocron"
)
func task() {
fmt.Println("I am runnning task.", time.Now())
}
func vijay() {
fmt.Println("I am runnning vijay.", time.Now())
}
func main() {
s := gocron.NewScheduler()
s.Every(2).Seconds().Do(task)
s.Every(4).Seconds().Do(vijay)
sc := s.Start() // keep the channel
go test(s, sc) // wait
<-sc // it will happens if the channel is closed
}
func test(s *gocron.Scheduler, sc chan bool) {
time.Sleep(8 * time.Second)
s.Clear()
fmt.Println("All task removed")
close(sc) // close the channel
}

Related

How do you gracefully exit a go uber fx app

How do you stop an uber fx as in shutdown the entire program. There seems to be no other way other than ctrl+c
func main() {
fx.New(
fx.Invoke(register)
).Run
}
func register() {
time.Sleep(5*time.Seconds)
// shutdown somehow
}
The docs are not particularly clear, but there's a Shutdowner interface available to any Fx module with a Shutdown method that requests graceful application shutdown.
Here's a modified part of the example package that will have it simply shutdown upon receiving a request:
func NewHandler(logger *log.Logger, shutdowner fx.Shutdowner) (http.Handler, error) {
logger.Print("Executing NewHandler.")
return http.HandlerFunc(func(http.ResponseWriter, *http.Request) {
logger.Print("Got a request. Requesting shutdown now that I've gotten one request.")
shutdowner.Shutdown()
}), nil
}
Edit: Here's how you could modify your solution:
func register(shutdowner fx.Shutdowner) {
time.Sleep(5*time.Seconds)
shutdowner.Shutdown()
}
You can wrap it inside a go routine and use context to gracefully exit.
import (
"context"
"log"
" go.uber.org/fx"
)
func main() {
f := fx.New(fx.Invoke(register))
go func() {
f.Run()
}()
stopCh := make(chan os.Signal)
signal.Notify(stopCh, syscall.SIGINT, syscall.SIGTERM)
<-stopCh
if err := f.Stop(context.Background()); err != nil {
log.Printf("error stopping gracefully")
}
}
func register() {
time.Sleep(5*time.Seconds)
// shutdown somehow
}

How to pause and resume goroutine?

I am trying to pause and resume groutine. I understand I can sleep the run, but I am looking for is like a button "pause/resume" rather than a timer.
Here is my attempt. I am using the blocking feature of channel to pause, and select to switch what to execute based on channel value. However, the output is always Running in my case.
func main() {
ctx := wctx{}
go func(ctx wctx) {
for {
time.Sleep(1 * time.Second)
select {
case <-ctx.pause:
fmt.Print("Paused")
<-ctx.pause
case <-ctx.resume:
fmt.Print("Resumed")
default:
fmt.Print("Running \n")
}
}
}(ctx)
ctx.pause <- struct{}{}
ctx.resume <- struct{}{}
}
type wctx struct {
pause chan struct{}
resume chan struct{}
}
A select with multiple ready cases chooses one pseudo-randomly. So if the goroutine is "slow" to check those channels, you might send a value on both pause and resume (assuming they are buffered) so receiving from both channels could be ready, and resume could be chosen first, and in a later iteration the pause when the goroutine should not be paused anymore.
For this you should use a "state" variable synchronized by a mutex. Something like this:
const (
StateRunning = iota
StatePaused
)
type wctx struct {
mu sync.Mutex
state int
}
func (w *wctx) SetState(state int) {
w.mu.Lock()
defer w.mu.Unlock()
w.state = state
}
func (w *wctx) State() int {
w.mu.Lock()
defer w.mu.Unlock()
return w.state
}
Testing it:
ctx := &wctx{}
go func(ctx *wctx) {
for {
time.Sleep(1 * time.Millisecond)
switch state := ctx.State(); state {
case StatePaused:
fmt.Println("Paused")
default:
fmt.Println("Running")
}
}
}(ctx)
time.Sleep(3 * time.Millisecond)
ctx.SetState(StatePaused)
time.Sleep(3 * time.Millisecond)
ctx.SetState(StateRunning)
time.Sleep(2 * time.Millisecond)
Output (try it on the Go Playground):
Running
Running
Running
Paused
Paused
Paused
Running
Running
You need to initialize your channels, remember that reads from nil channels always blocks.
A select with a default case never blocks.
Here is a modified version of your program, that fixes the above mentioned issues:
package main
import (
"fmt"
"time"
)
func main() {
ctx := wctx{
pause: make(chan struct{}),
resume: make(chan struct{}),
}
go func(ctx wctx) {
for {
select {
case <-ctx.pause:
fmt.Println("Paused")
case <-ctx.resume:
fmt.Println("Resumed")
}
fmt.Println("Running")
time.Sleep(time.Second)
}
}(ctx)
ctx.pause <- struct{}{}
ctx.resume <- struct{}{}
}
type wctx struct {
pause chan struct{}
resume chan struct{}
}

Running multiple methods periodically

I'm new to go and trying to make two methods run at the same time periodically for as long at the application is running. I've managed to come up with the following but the for true part does not feel right as this is blocking.
Would channels be a better way todo this? Any pointers in the right direction would be helpful.
func main() {
t1 := schedule(ping, time.Second)
t2 := schedule(ping, 2*time.Second)
for true {
time.Sleep(1 * time.Second)
}
t1.Stop()
t2.Stop()
}
func schedule(f func(interval time.Duration), interval time.Duration) *time.Ticker {
ticker := time.NewTicker(interval)
go func() {
for range ticker.C {
f(interval)
}
}()
return ticker
}
func ping(interval time.Duration) {
log.Println("ping ", interval)
}
To prevent the application from exiting, the main goroutine must block.
Use select {} to block the main goroutine.
Because the tickers run for the duration of the application, there's no need to stop the tickers.
func main() {
schedule(ping, time.Second)
schedule(ping, 2*time.Second)
select {}
}

How to test that a function was called in a goroutine?

I'd like to make sure that we're starting a goroutine by calling a function with the right arguments.
For example:
func MyTest(t *testing.T) {
service.EXPECT().MyMockFunc(1)
service.MyFunc()
}
func MyFunc() {
go MyMockFunc(1)
}
When I run this test, it fails because (I believe) MyMockFunc only gets called after the test has already finished running.
Is there a way to test that I started a goroutine by calling a function with the right arguments?
Note: Ideally, I'd like to keep the arguments I pass to MyMockFunc as is (not add a channel arg for instance).
Using a channel and assuming you can fire the goroutine from the test:
package main
import (
"fmt"
"testing"
"time"
)
func MyMockFunc(n int) int {
fmt.Println("MyMockFunc is called")
time.Sleep(5 * time.Second)
return n + 1
}
func TestMyMockFunc(t *testing.T) {
result := make(chan int)
go func() {
result <- MyMockFunc(1)
}()
if <-result != 2 {
t.Fatalf("Expecting 2")
}
}

Reading from map with locks doesn't return value via channel

I tried to implement a locking version of reading/writing from a map in golang, but it doesn't return the desired result.
package main
import (
"sync"
"fmt"
)
var m = map[int]string{}
var lock = sync.RWMutex{}
func StoreUrl(id int, url string) {
for {
lock.Lock()
defer lock.Unlock()
m[id] = url
}
}
func LoadUrl(id int, ch chan string) {
for {
lock.RLock()
defer lock.RUnlock()
r := m[id]
ch <- r
}
}
func main() {
go StoreUrl(125, "www.google.com")
chb := make(chan string)
go LoadUrl(125, chb);
C := <-chb
fmt.Println("Result:", C)
}
The output is:
Result:
Meaning the value is not returned via the channel, which I don't get. Without the locking/goroutines it seems to work fine. What did I do wrong?
The code can also be found here:
https://play.golang.org/p/-WmRcMty5B
Infinite loops without sleep or some kind of IO are always bad idea.
In your code if you put a print statement at the start of StoreUrl, you will find that it never gets printed i.e the go routine was never started, the go call is setting putting the info about this new go routine in some run queue of the go scheduler but the scheduler hasn't ran yet to schedule that task. How do you run the scheduler? Do sleep/IO/channel reading/writing.
Another problem is that your infinite loop is taking lock and trying to take the lock again, which will cause it to deadlock. Defer only run after function exit and that function will never exit because of infinite loop.
Below is modified code that uses sleep to make sure every execution thread gets time to do its job.
package main
import (
"sync"
"fmt"
"time"
)
var m = map[int]string{}
var lock = sync.RWMutex{}
func StoreUrl(id int, url string) {
for {
lock.Lock()
m[id] = url
lock.Unlock()
time.Sleep(1)
}
}
func LoadUrl(id int, ch chan string) {
for {
lock.RLock()
r := m[id]
lock.RUnlock()
ch <- r
}
}
func main() {
go StoreUrl(125, "www.google.com")
time.Sleep(1)
chb := make(chan string)
go LoadUrl(125, chb);
C := <-chb
fmt.Println("Result:", C)
}
Edit: As #Jaun mentioned in the comment, you can also use runtime.Gosched() instead of sleep.
Usage of defer incorrect, defer execute at end of function, not for statement.
func StoreUrl(id int, url string) {
for {
func() {
lock.Lock()
defer lock.Unlock()
m[id] = url
}()
}
}
or
func StoreUrl(id int, url string) {
for {
lock.Lock()
m[id] = url
lock.Unlock()
}
}
We can't control the order of go routine, so add time.Sleep() to control the order.
code here:
https://play.golang.org/p/Bu8Lo46SA2

Resources