-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #31 from sev-2/feature/scheduler
Feature : support scheduler
- Loading branch information
Showing
9 changed files
with
331 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
package generator | ||
|
||
import ( | ||
"fmt" | ||
"io/fs" | ||
"path/filepath" | ||
"strings" | ||
|
||
"github.com/hashicorp/go-hclog" | ||
"github.com/sev-2/raiden/pkg/logger" | ||
"github.com/sev-2/raiden/pkg/utils" | ||
) | ||
|
||
var JobRegisterLogger hclog.Logger = logger.HcLog().Named("generator.job_register") | ||
|
||
// ----- Define type, variable and constant ----- | ||
type ( | ||
GenerateRegisterJobData struct { | ||
Imports []string | ||
Package string | ||
Jobs []string | ||
} | ||
) | ||
|
||
const ( | ||
JobRegisterFilename = "jobs.go" | ||
JobRegisterDir = "internal/bootstrap" | ||
JobDir = "internal/jobs" | ||
JobRegisterTemplate = `// Code generated by raiden-cli; DO NOT EDIT. | ||
package {{ .Package }} | ||
{{if gt (len .Imports) 0 }} | ||
import ( | ||
{{- range .Imports}} | ||
{{.}} | ||
{{- end}} | ||
) | ||
{{end }} | ||
func RegisterJobs(server *raiden.Server) { | ||
server.RegisterJobs( | ||
{{- range .Jobs}} | ||
&jobs.{{.}}{}, | ||
{{- end}} | ||
) | ||
} | ||
` | ||
) | ||
|
||
func GenerateJobRegister(basePath string, projectName string, generateFn GenerateFn) error { | ||
jobRegisterDir := filepath.Join(basePath, JobRegisterDir) | ||
JobRegisterLogger.Trace("create bootstrap folder if not exist", "path", jobRegisterDir) | ||
if exist := utils.IsFolderExists(jobRegisterDir); !exist { | ||
if err := utils.CreateFolder(jobRegisterDir); err != nil { | ||
return err | ||
} | ||
} | ||
|
||
jobDir := filepath.Join(basePath, JobDir) | ||
JobRegisterLogger.Trace("create job folder if not exist", "path", jobDir) | ||
if exist := utils.IsFolderExists(jobDir); !exist { | ||
if err := utils.CreateFolder(jobDir); err != nil { | ||
return err | ||
} | ||
} | ||
|
||
// scan all controller | ||
jobList, err := WalkScanJob(jobDir) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
input, err := createRegisterJobInput(projectName, jobRegisterDir, jobList) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
JobRegisterLogger.Debug("generate job", "path", input.OutputPath) | ||
return generateFn(input, nil) | ||
} | ||
|
||
func createRegisterJobInput(projectName string, jobRegisterDir string, jobList []string) (input GenerateInput, err error) { | ||
// set file path | ||
filePath := filepath.Join(jobRegisterDir, JobRegisterFilename) | ||
|
||
// set imports path | ||
imports := []string{ | ||
fmt.Sprintf("%q", "github.com/sev-2/raiden"), | ||
} | ||
|
||
if len(jobList) > 0 { | ||
rpcImportPath := fmt.Sprintf("%s/internal/jobs", utils.ToGoModuleName(projectName)) | ||
imports = append(imports, fmt.Sprintf("%q", rpcImportPath)) | ||
} | ||
|
||
// set passed parameter | ||
data := GenerateRegisterJobData{ | ||
Package: "bootstrap", | ||
Imports: imports, | ||
Jobs: jobList, | ||
} | ||
|
||
input = GenerateInput{ | ||
BindData: data, | ||
Template: JobRegisterTemplate, | ||
TemplateName: "jobRegisterTemplate", | ||
OutputPath: filePath, | ||
} | ||
|
||
return | ||
} | ||
|
||
func WalkScanJob(jobDir string) ([]string, error) { | ||
RpcRegisterLogger.Trace("scan all job", "path", jobDir) | ||
|
||
job := make([]string, 0) | ||
err := filepath.Walk(jobDir, func(path string, info fs.FileInfo, err error) error { | ||
if strings.HasSuffix(path, ".go") { | ||
RpcRegisterLogger.Trace("collect job", "path", path) | ||
rs, e := getStructByBaseName(path, "JobBase") | ||
if e != nil { | ||
return e | ||
} | ||
job = append(job, rs...) | ||
} | ||
return nil | ||
}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return job, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
package raiden | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/go-co-op/gocron/v2" | ||
"github.com/google/uuid" | ||
"github.com/sev-2/raiden/pkg/logger" | ||
) | ||
|
||
var SchedulerLogger = logger.HcLog().Named("raiden.scheduler") | ||
|
||
// ----- Custom Type | ||
type ScheduleStatus string | ||
|
||
const ( | ||
ScheduleStatusOn ScheduleStatus = "on" | ||
ScheduleStatusOff ScheduleStatus = "off" | ||
) | ||
|
||
// ----- Scheduler Base | ||
type JobDuration = gocron.JobDefinition | ||
type Job interface { | ||
Name() string | ||
Duration() JobDuration | ||
After(cfg *Config, jobID uuid.UUID, jobName string) | ||
AfterErr(cfg *Config, jobID uuid.UUID, jobName string, err error) | ||
Before(cfg *Config, jobID uuid.UUID, jobName string) | ||
Task(cfg *Config) error | ||
} | ||
|
||
type JobBase struct{} | ||
|
||
func (j *JobBase) Duration() JobDuration { | ||
return nil | ||
} | ||
|
||
func (j *JobBase) After(cfg *Config, jobID uuid.UUID, jobName string) {} | ||
|
||
func (j *JobBase) AfterErr(cfg *Config, jobID uuid.UUID, jobName string, err error) {} | ||
|
||
func (j *JobBase) Before(cfg *Config, jobID uuid.UUID, jobName string) {} | ||
|
||
func (j *JobBase) Task(cfg *Config) error { | ||
return nil | ||
} | ||
|
||
// ----- Scheduler server | ||
func NewSchedulerServer(cfg *Config, options ...gocron.SchedulerOption) (*SchedulerServer, error) { | ||
server, err := gocron.NewScheduler(options...) | ||
if err != nil { | ||
SchedulerLogger.Error(err.Error()) | ||
return nil, err | ||
} | ||
|
||
return &SchedulerServer{ | ||
Config: cfg, | ||
Server: server, | ||
}, nil | ||
|
||
} | ||
|
||
type SchedulerServer struct { | ||
Config *Config | ||
Server gocron.Scheduler | ||
} | ||
|
||
func (s *SchedulerServer) RegisterJob(job Job) error { | ||
options := make([]gocron.JobOption, 0) | ||
|
||
// setup job name | ||
options = append(options, gocron.WithName(job.Name())) | ||
|
||
// setup job event listener | ||
options = append(options, gocron.WithEventListeners( | ||
gocron.AfterJobRuns(func(jobID uuid.UUID, jobName string) { | ||
job.After(s.Config, jobID, jobName) | ||
}), | ||
gocron.AfterJobRunsWithError(func(jobID uuid.UUID, jobName string, err error) { | ||
job.AfterErr(s.Config, jobID, jobName, err) | ||
}), | ||
gocron.BeforeJobRuns(func(jobID uuid.UUID, jobName string) { | ||
job.Before(s.Config, jobID, jobName) | ||
}), | ||
)) | ||
|
||
j, err := s.Server.NewJob(job.Duration(), gocron.NewTask(func() (err error) { | ||
defer func() { | ||
if r := recover(); r != nil { | ||
err = fmt.Errorf("%v", r) | ||
} | ||
}() | ||
err = job.Task(s.Config) | ||
return | ||
}), options...) | ||
if err != nil { | ||
SchedulerLogger.Error("failed run job", "name", job.Name()) | ||
return err | ||
} | ||
|
||
SchedulerLogger.Info("start run job", "id", j.ID(), "name", j.Name()) | ||
return nil | ||
} | ||
|
||
// ----- TODO | ||
// 1. make auto create `schedule_log` to save all job report | ||
// 2. make function to record report job after running and save to database |
Oops, something went wrong.