I'm writing the basics of a custom scheduling tool, which will read a config file for "jobs" and add them to the schedule to run the periodically. It's very basic for now, like a proof of concept before refactoring and some additional more advanced features.
When I try to run this program, it reports that the script is not found. The script "test1.sh" does exist in the path where I'm trying to run it from, and it has execute permissions.
I'm getting the following error, but can't explain it or work it out as the script does exist at the path I'm running it:
-> ./scheduler-example
2021/08/16 12:48:54 fork/exec /Users/me/scheduler-example/scripts/test1.sh: no such file or directory
The scheduler code:
package main
import (
"io"
"log"
"os"
"os/exec"
"path/filepath"
"time"
"github.com/go-co-op/gocron"
"gopkg.in/yaml.v3"
)
type Config struct {
GlobalLog string `yaml:"GlobalLog"`
Jobs []Job `yaml:"Jobs"`
}
type Job struct {
Name string `yaml:"Name"`
Command string `yaml:"Command"`
Frequency string `yaml:"Frequency"`
Tag string `yaml:"Tag,omitempty"`
Log string `yaml:"Log,omitempty"`
}
const ROOT string = "/Users/me/scheduler-example"
func main() {
// STEP1: Parse the config file
configFile := filepath.Join(ROOT, "config", "scheduler-example.yaml")
f, err := os.Open(configFile)
if err != nil {
log.Fatalln(err)
}
configData, err := io.ReadAll(f)
if err != nil {
log.Fatalln(err)
}
c := Config{}
err = yaml.Unmarshal(configData, &c)
if err != nil {
log.Fatalln(err)
}
// STEP2: Validate the config
if c.GlobalLog == "" {
log.Fatalln("Global log not defined")
}
if c.Jobs == nil {
log.Fatalln("No jobs defined")
}
for _, j := range c.Jobs {
if j.Name == "" {
log.Fatalln("Job name not defined")
}
if j.Command == "" {
log.Fatalln("Job command not defined")
}
if j.Frequency == "" {
log.Fatalln("Job frequency not defined")
}
}
// STEP3: Create the scheduler and add jobs
s := gocron.NewScheduler(time.UTC)
for _, j := range c.Jobs {
script := filepath.Join(ROOT, "scripts", j.Command)
cmd := exec.Command(script)
cmdLog := filepath.Join(ROOT, "logs", j.Log)
l, err := os.OpenFile(cmdLog, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)
if err != nil {
log.Fatalln(err)
}
cmd.Stdout = l
cmd.Stderr = l
freq := j.Frequency
tag := j.Tag
s.Every(freq).Tag(tag).Do(func() {
err = cmd.Run()
if err != nil {
log.Fatalln(err)
}
})
}
// STEP4: Run the scheduler
s.StartBlocking()
}
Config file:
GlobalLog: /tmp/scheduler-example.log
Jobs:
- Name: test1
Command: test1.sh
Frequency: 5s
Tag: test1
Log: test1.log
- Name: test2
Command: test2.sh
Frequency: 5s
Tag: test2
Log: test2.log
Directory structure:
-> tree .
.
├── config
│ └── scheduler-example.yaml
├── go.mod
├── go.sum
├── logs
│ ├── test1.log
│ └── test2.log
├── scheduler-example.go
└── scripts
├── test1.sh
└── test2.sh
3 directories, 8 files
The test1.sh script:
#!/bin/env bash
for i in {1..100}; do
echo i
sleep 10
done
Thanks for any and all help!