Skip to content

Commit da39040

Browse files
authored
Merge pull request #212 from ninech/sched
add scheduled jobs
2 parents a71de0b + a8c9704 commit da39040

File tree

9 files changed

+120
-45
lines changed

9 files changed

+120
-45
lines changed

create/application.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ type applicationCmd struct {
4545
BuildEnv map[string]string `help:"Environment variables which are passed to the app build process."`
4646
DeployJob deployJob `embed:"" prefix:"deploy-job-"`
4747
WorkerJob workerJob `embed:"" prefix:"worker-job-"`
48+
ScheduledJob scheduledJob `embed:"" prefix:"scheduled-job-"`
4849
GitInformationServiceURL string `help:"URL of the git information service." default:"https://git-info.deplo.io" env:"GIT_INFORMATION_SERVICE_URL" hidden:""`
4950
SkipRepoAccessCheck bool `help:"Skip the git repository access check" default:"false"`
5051
Debug bool `help:"Enable debug messages" default:"false"`
@@ -75,6 +76,13 @@ type workerJob struct {
7576
Size *string `help:"Size of the worker (defaults to \"${app_default_size}\")." placeholder:"${app_default_size}"`
7677
}
7778

79+
type scheduledJob struct {
80+
Command string `help:"Command to execute to start the scheduled job." placeholder:"\"bundle exec rails runner\""`
81+
Name string `help:"Name of the scheduled job job to add." placeholder:"scheduled-1"`
82+
Size *string `help:"Size (resources) of the scheduled job (defaults to \"${app_default_size}\")." placeholder:"${app_default_size}"`
83+
Schedule string `help:"Cron notation string for the scheduled job (defaults to \"* * * * *\")." placeholder:"* * * * *"`
84+
}
85+
7886
type dockerfileBuild struct {
7987
Enabled bool `name:"dockerfile" help:"${app_dockerfile_enable_help}" default:"false"`
8088
Path string `name:"dockerfile-path" help:"${app_dockerfile_path_help}" default:""`
@@ -298,6 +306,20 @@ func (app *applicationCmd) config() apps.Config {
298306
config.WorkerJobs = append(config.WorkerJobs, workerJob)
299307
}
300308

309+
if len(app.ScheduledJob.Command) != 0 && len(app.ScheduledJob.Name) != 0 && len(app.ScheduledJob.Schedule) != 0 {
310+
scheduledJob := apps.ScheduledJob{
311+
Job: apps.Job{
312+
Name: app.ScheduledJob.Name,
313+
Command: app.ScheduledJob.Command,
314+
},
315+
Schedule: app.ScheduledJob.Schedule,
316+
}
317+
if app.ScheduledJob.Size != nil {
318+
scheduledJob.Size = ptr.To(apps.ApplicationSize(*app.ScheduledJob.Size))
319+
}
320+
config.ScheduledJobs = append(config.ScheduledJobs, scheduledJob)
321+
}
322+
301323
if app.Size != nil {
302324
config.Size = apps.ApplicationSize(*app.Size)
303325
}

create/mysql_test.go

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package create
33
import (
44
"context"
55
"errors"
6-
"reflect"
76
"testing"
87
"time"
98

@@ -114,17 +113,7 @@ func TestMySQL(t *testing.T) {
114113
return
115114
}
116115

117-
// we set defaults for the slices
118-
if tt.want.AllowedCIDRs == nil {
119-
tt.want.AllowedCIDRs = []meta.IPv4CIDR{}
120-
}
121-
if tt.want.SSHKeys == nil {
122-
tt.want.SSHKeys = []storage.SSHKey{}
123-
}
124-
125-
if !reflect.DeepEqual(created.Spec.ForProvider, tt.want) {
126-
t.Fatalf("expected mysql.Spec.ForProvider = %+v, got: %+v", created.Spec.ForProvider, tt.want)
127-
}
116+
require.Equal(t, tt.want, created.Spec.ForProvider)
128117
})
129118
}
130119
}

create/postgres_test.go

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package create
33
import (
44
"context"
55
"errors"
6-
"reflect"
76
"testing"
87
"time"
98

@@ -94,17 +93,7 @@ func TestPostgres(t *testing.T) {
9493
return
9594
}
9695

97-
// we set defaults for the slices
98-
if tt.want.AllowedCIDRs == nil {
99-
tt.want.AllowedCIDRs = []meta.IPv4CIDR{}
100-
}
101-
if tt.want.SSHKeys == nil {
102-
tt.want.SSHKeys = []storage.SSHKey{}
103-
}
104-
105-
if !reflect.DeepEqual(created.Spec.ForProvider, tt.want) {
106-
t.Fatalf("expected postgres.Spec.ForProvider = %+v, got: %+v", created.Spec.ForProvider, tt.want)
107-
}
96+
require.Equal(t, tt.want, created.Spec.ForProvider)
10897
})
10998
}
11099
}

get/application.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ func printApplication(apps []apps.Application, get *Cmd, out io.Writer, header b
8383
w := tabwriter.NewWriter(out, 0, 0, 4, ' ', 0)
8484

8585
if header {
86-
get.writeHeader(w, "NAME", "REPLICAS", "WORKERJOBS", "HOSTS", "UNVERIFIEDHOSTS")
86+
get.writeHeader(w, "NAME", "REPLICAS", "WORKERJOBS", "SCHEDULEDJOBS", "HOSTS", "UNVERIFIEDHOSTS")
8787
}
8888

8989
for _, app := range apps {
@@ -94,8 +94,9 @@ func printApplication(apps []apps.Application, get *Cmd, out io.Writer, header b
9494
replicas = int(*app.Status.AtProvider.Replicas)
9595
}
9696
workerJobs := fmt.Sprintf("%d", len(app.Status.AtProvider.WorkerJobs))
97+
scheduledJobs := fmt.Sprintf("%d", len(app.Status.AtProvider.ScheduledJobs))
9798

98-
get.writeTabRow(w, app.Namespace, app.Name, fmt.Sprintf("%d", replicas), workerJobs, join(verifiedHosts), join(unverifiedHosts))
99+
get.writeTabRow(w, app.Namespace, app.Name, fmt.Sprintf("%d", replicas), workerJobs, scheduledJobs, join(verifiedHosts), join(unverifiedHosts))
99100
}
100101

101102
return w.Flush()
@@ -214,6 +215,10 @@ func (cmd *applicationsCmd) printStats(ctx context.Context, c *api.Client, appLi
214215
workers = append(workers, wjs.ReplicaObservation...)
215216
}
216217

218+
for _, sjs := range rel.Status.AtProvider.ScheduledJobStatus {
219+
workers = append(workers, sjs.ReplicaObservation...)
220+
}
221+
217222
for _, replica := range append(replicas, workers...) {
218223
podMetrics := metricsv1beta1.PodMetrics{}
219224
if err := runtimeClient.Get(ctx, api.NamespacedName(replica.ReplicaName, app.Namespace), &podMetrics); err != nil {

get/releases.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ func (cmd *releasesCmd) printReleases(releases []apps.Release, get *Cmd, header
6464
"SIZE",
6565
"REPLICAS",
6666
"WORKERJOBS",
67+
"SCHEDULEDJOBS",
6768
"STATUS",
6869
"AGE",
6970
)
@@ -78,6 +79,7 @@ func (cmd *releasesCmd) printReleases(releases []apps.Release, get *Cmd, header
7879
replicas = strconv.Itoa(int(*r.Spec.ForProvider.Config.Replicas))
7980
}
8081
workerJobs := strconv.Itoa(len(r.Spec.ForProvider.Config.WorkerJobs))
82+
scheduledJobs := strconv.Itoa(len(r.Spec.ForProvider.Config.ScheduledJobs))
8183

8284
get.writeTabRow(
8385
w,
@@ -88,6 +90,7 @@ func (cmd *releasesCmd) printReleases(releases []apps.Release, get *Cmd, header
8890
string(r.Spec.ForProvider.Config.Size),
8991
replicas,
9092
workerJobs,
93+
scheduledJobs,
9194
string(r.Status.AtProvider.ReleaseStatus),
9295
duration.HumanDuration(time.Since(r.ObjectMeta.CreationTimestamp.Time)),
9396
)

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ require (
2626
github.com/mattn/go-isatty v0.0.20
2727
github.com/moby/moby v27.1.1+incompatible
2828
github.com/moby/term v0.5.0
29-
github.com/ninech/apis v0.0.0-20250120083942-90d315ad8c32
29+
github.com/ninech/apis v0.0.0-20250304140759-2e6d16e9749f
3030
github.com/posener/complete v1.2.3
3131
github.com/prometheus/common v0.55.0
3232
github.com/stretchr/testify v1.9.0

go.sum

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,12 @@ github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+
597597
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
598598
github.com/ninech/apis v0.0.0-20250120083942-90d315ad8c32 h1:0XaOKTYVCIVd+oqG+7Km9j2/hVqkB4U7ySyEw15KvF0=
599599
github.com/ninech/apis v0.0.0-20250120083942-90d315ad8c32/go.mod h1:6srtlYi3nj8GRxQkbhvSbanIBc9vsoPLFOp5VQzNNhM=
600+
github.com/ninech/apis v0.0.0-20250304140759-2e6d16e9749f h1:3RXpRcPZKkw2rE7TyuFk8e+tWr8Mhl8bZqTDFm0ybWM=
601+
github.com/ninech/apis v0.0.0-20250304140759-2e6d16e9749f/go.mod h1:6srtlYi3nj8GRxQkbhvSbanIBc9vsoPLFOp5VQzNNhM=
602+
github.com/ninech/apis v0.0.0-20250304143335-386c5bf8bc63 h1:B8UqsTldPq5j2kLrkOsi++2jd1b5hk/O+yVrlR+AnVY=
603+
github.com/ninech/apis v0.0.0-20250304143335-386c5bf8bc63/go.mod h1:6srtlYi3nj8GRxQkbhvSbanIBc9vsoPLFOp5VQzNNhM=
604+
github.com/ninech/apis v0.0.0-20250305125840-3bc1e01edb09 h1:vihjujYXJAgRSa5VQgtpVkWNRcd3DccVbUn6PliMrgQ=
605+
github.com/ninech/apis v0.0.0-20250305125840-3bc1e01edb09/go.mod h1:6srtlYi3nj8GRxQkbhvSbanIBc9vsoPLFOp5VQzNNhM=
600606
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
601607
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
602608
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=

logs/application.go

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111
type applicationCmd struct {
1212
resourceCmd
1313
logsCmd
14-
Type appLogType `short:"t" help:"Which type of app logs to output. ${enum}" enum:"all,app,build,worker_job,deploy_job" default:"all"`
14+
Type appLogType `short:"t" help:"Which type of app logs to output. ${enum}" enum:"all,app,build,worker_job,deploy_job,scheduled_job" default:"all"`
1515
}
1616

1717
func (cmd *applicationCmd) Run(ctx context.Context, client *api.Client) error {
@@ -26,7 +26,7 @@ func (cmd *applicationCmd) Run(ctx context.Context, client *api.Client) error {
2626
cmd.Type.queryExpressions(),
2727
inProject(client.Project),
2828
queryExpr(opEquals, apps.LogLabelApplication, cmd.Name))...),
29-
apps.LogLabelBuild, apps.LogLabelReplica, apps.LogLabelWorkerJob, apps.LogLabelDeployJob,
29+
apps.LogLabelBuild, apps.LogLabelReplica, apps.LogLabelWorkerJob, apps.LogLabelDeployJob, apps.LogLabelDeployJob,
3030
)
3131
}
3232

@@ -41,11 +41,12 @@ func ApplicationQuery(name, project string) string {
4141
type appLogType string
4242

4343
const (
44-
logTypeAll appLogType = "all"
45-
logTypeApp appLogType = "app"
46-
logTypeBuild appLogType = "build"
47-
logTypeDeployJob appLogType = "deploy_job"
48-
logTypeWorkerJob appLogType = "worker_job"
44+
logTypeAll appLogType = "all"
45+
logTypeApp appLogType = "app"
46+
logTypeBuild appLogType = "build"
47+
logTypeDeployJob appLogType = "deploy_job"
48+
logTypeWorkerJob appLogType = "worker_job"
49+
logTypeScheduledJob appLogType = "scheduled_job"
4950
)
5051

5152
func (a appLogType) queryExpressions() []string {
@@ -57,13 +58,16 @@ func (a appLogType) queryExpressions() []string {
5758
expr = append(expr,
5859
queryExpr(opEquals, apps.LogLabelDeployJob, ""),
5960
queryExpr(opEquals, apps.LogLabelWorkerJob, ""),
61+
queryExpr(opEquals, apps.LogLabelScheduledJob, ""),
6062
queryExpr(opEquals, apps.LogLabelBuild, ""))
6163
case logTypeBuild:
6264
expr = append(expr, queryExpr(opNotEquals, apps.LogLabelBuild, ""))
6365
case logTypeDeployJob:
6466
expr = append(expr, queryExpr(opNotEquals, apps.LogLabelDeployJob, ""))
6567
case logTypeWorkerJob:
6668
expr = append(expr, queryExpr(opNotEquals, apps.LogLabelWorkerJob, ""))
69+
case logTypeScheduledJob:
70+
expr = append(expr, queryExpr(opNotEquals, apps.LogLabelScheduledJob, ""))
6771
}
6872
return expr
6973
}

update/application.go

Lines changed: 68 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ type applicationCmd struct {
3737
DeleteBuildEnv *[]string `help:"Build environment variables which are to be deleted."`
3838
DeployJob *deployJob `embed:"" prefix:"deploy-job-"`
3939
WorkerJob *workerJob `embed:"" prefix:"worker-job-"`
40+
ScheduledJob *scheduledJob `embed:"" prefix:"scheduled-job-"`
4041
DeleteWorkerJob *string `help:"Delete a worker job by name"`
42+
DeleteScheduledJob *string `help:"Delete a scheduled job by name"`
4143
RetryBuild *bool `help:"Retries build for the application if set to true." placeholder:"false"`
4244
GitInformationServiceURL string `help:"URL of the git information service." default:"https://git-info.deplo.io" env:"GIT_INFORMATION_SERVICE_URL" hidden:""`
4345
SkipRepoAccessCheck bool `help:"Skip the git repository access check" default:"false"`
@@ -91,6 +93,13 @@ type workerJob struct {
9193
Size *string `help:"Size of the worker (defaults to \"${app_default_size}\")." placeholder:"${app_default_size}"`
9294
}
9395

96+
type scheduledJob struct {
97+
Command *string `help:"Command to execute to start the scheduled job." placeholder:"\"bundle exec rails runner\""`
98+
Name *string `help:"Name of the scheduled job job to add." placeholder:"scheduled-1"`
99+
Size *string `help:"Size (resources) of the scheduled job (defaults to \"${app_default_size}\")." placeholder:"${app_default_size}"`
100+
Schedule *string `help:"Cron notation string for the scheduled job (defaults to \"* * * * *\")." placeholder:"* * * * *"`
101+
}
102+
94103
type dockerfileBuild struct {
95104
Path *string `name:"dockerfile-path" help:"${app_dockerfile_path_help}" placeholder:"."`
96105
BuildContext *string `name:"dockerfile-build-context" help:"${app_dockerfile_build_context_help}" placeholder:"."`
@@ -225,6 +234,12 @@ func (cmd *applicationCmd) applyUpdates(app *apps.Application) {
225234
if cmd.DeleteWorkerJob != nil {
226235
deleteWorkerJob(*cmd.DeleteWorkerJob, &app.Spec.ForProvider.Config)
227236
}
237+
if cmd.ScheduledJob != nil {
238+
cmd.ScheduledJob.applyUpdates(&app.Spec.ForProvider.Config)
239+
}
240+
if cmd.DeleteScheduledJob != nil {
241+
deleteScheduledJob(*cmd.DeleteScheduledJob, &app.Spec.ForProvider.Config)
242+
}
228243
if cmd.Language != nil {
229244
app.Spec.ForProvider.Language = apps.Language(*cmd.Language)
230245
}
@@ -297,29 +312,26 @@ func (job workerJob) applyUpdates(cfg *apps.Config) {
297312
if job.Name == nil {
298313
return
299314
}
300-
found := false
301315
for i := range cfg.WorkerJobs {
302316
if cfg.WorkerJobs[i].Name == *job.Name {
303-
found = true
304317
if job.Command != nil {
305318
cfg.WorkerJobs[i].Command = *job.Command
306319
}
307320
if job.Size != nil {
308321
cfg.WorkerJobs[i].Size = ptr.To(apps.ApplicationSize(*job.Size))
309322
}
323+
return
310324
}
311325
}
312326

313-
if !found {
314-
newJob := apps.WorkerJob{Job: apps.Job{Name: *job.Name}}
315-
if job.Command != nil {
316-
newJob.Command = *job.Command
317-
}
318-
if job.Size != nil {
319-
newJob.Size = ptr.To(apps.ApplicationSize(*job.Size))
320-
}
321-
cfg.WorkerJobs = append(cfg.WorkerJobs, newJob)
327+
newJob := apps.WorkerJob{Job: apps.Job{Name: *job.Name}}
328+
if job.Command != nil {
329+
newJob.Command = *job.Command
322330
}
331+
if job.Size != nil {
332+
newJob.Size = ptr.To(apps.ApplicationSize(*job.Size))
333+
}
334+
cfg.WorkerJobs = append(cfg.WorkerJobs, newJob)
323335
}
324336

325337
func deleteWorkerJob(name string, cfg *apps.Config) {
@@ -336,6 +348,51 @@ func deleteWorkerJob(name string, cfg *apps.Config) {
336348
cfg.WorkerJobs = newJobs
337349
}
338350

351+
func (job scheduledJob) applyUpdates(cfg *apps.Config) {
352+
if job.Name == nil {
353+
format.PrintWarningf("you need to pass a job name to update the command, schedule or size\n")
354+
return
355+
}
356+
357+
for i := range cfg.ScheduledJobs {
358+
if cfg.ScheduledJobs[i].Name == *job.Name {
359+
if job.Command != nil {
360+
cfg.ScheduledJobs[i].Command = *job.Command
361+
}
362+
if job.Size != nil {
363+
cfg.ScheduledJobs[i].Size = ptr.To(apps.ApplicationSize(*job.Size))
364+
}
365+
if job.Schedule != nil {
366+
cfg.ScheduledJobs[i].Schedule = *job.Schedule
367+
}
368+
return
369+
}
370+
}
371+
372+
newJob := apps.ScheduledJob{Job: apps.Job{Name: *job.Name}}
373+
if job.Command != nil {
374+
newJob.Command = *job.Command
375+
}
376+
if job.Size != nil {
377+
newJob.Size = ptr.To(apps.ApplicationSize(*job.Size))
378+
}
379+
cfg.ScheduledJobs = append(cfg.ScheduledJobs, newJob)
380+
}
381+
382+
func deleteScheduledJob(name string, cfg *apps.Config) {
383+
newJobs := []apps.ScheduledJob{}
384+
for _, sj := range cfg.ScheduledJobs {
385+
if sj.Name != name {
386+
newJobs = append(newJobs, sj)
387+
}
388+
}
389+
if len(cfg.ScheduledJobs) == len(newJobs) {
390+
format.PrintWarningf("did not find a scheduled job with the name %q\n", name)
391+
return
392+
}
393+
cfg.ScheduledJobs = newJobs
394+
}
395+
339396
func warnIfDockerfileNotEnabled(app *apps.Application, flag string) {
340397
if !app.Spec.ForProvider.DockerfileBuild.Enabled {
341398
format.PrintWarningf("updating %s has no effect as dockerfile builds are not enabled on this app\n", flag)

0 commit comments

Comments
 (0)