- Manager gains the apparatus JobManager surface: StartJob, UpdateJobState, UpdateMetadata, FailJob, CancelJob (is_canceled + STOPPED + River JobCancel), StopJob (STOPPED only), CheckIfCanceled and GetMetadata, all raw column writes so updated_at is untouched - serve starts the in-process worker unless queue.work_in_serve is false and stops it on shutdown; an app without jobs gets an idle worker - queue:work runs a foreground worker with repeatable --queue filters; queue:clear deletes available, scheduled and retryable jobs of one queue - the generated main appends conga.RuntimeCommands; summer delegates queue:work and queue:clear; make:job scaffolds a conga.Job
117 lines
2.9 KiB
Go
117 lines
2.9 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"git.golem15.com/golem15/summercms/modules/bonfire"
|
|
"git.golem15.com/golem15/summercms/internal/build"
|
|
)
|
|
|
|
func delegateCommand(name, description string) bonfire.Command {
|
|
return bonfire.Command{
|
|
Name: name,
|
|
Description: description,
|
|
Run: func(ctx context.Context, in bonfire.Input, out bonfire.Output) error {
|
|
argv := []string{name}
|
|
argv = append(argv, in.Args()...)
|
|
return runAppBinary(ctx, argv, out)
|
|
},
|
|
}
|
|
}
|
|
|
|
func delegateRollbackCommand() bonfire.Command {
|
|
return bonfire.Command{
|
|
Name: "migrate:rollback",
|
|
Description: "Roll back the last migration of a plugin in the app binary",
|
|
Flags: []bonfire.Flag{{
|
|
Name: "plugin",
|
|
Description: "Plugin ID whose last migration to roll back",
|
|
}},
|
|
Run: func(ctx context.Context, in bonfire.Input, out bonfire.Output) error {
|
|
argv := []string{"migrate:rollback"}
|
|
if plugin, ok := in.Flag("plugin"); ok && plugin != "" {
|
|
argv = append(argv, "--plugin", plugin)
|
|
}
|
|
argv = append(argv, in.Args()...)
|
|
return runAppBinary(ctx, argv, out)
|
|
},
|
|
}
|
|
}
|
|
|
|
func delegateQueueWorkCommand() bonfire.Command {
|
|
return bonfire.Command{
|
|
Name: "queue:work",
|
|
Description: "Run background job workers in the app binary",
|
|
Flags: []bonfire.Flag{{
|
|
Name: "queue",
|
|
Description: "Queue to work (repeatable; default all known queues)",
|
|
Repeatable: true,
|
|
}},
|
|
Run: func(ctx context.Context, in bonfire.Input, out bonfire.Output) error {
|
|
argv := []string{"queue:work"}
|
|
for _, q := range in.Flags("queue") {
|
|
argv = append(argv, "--queue", q)
|
|
}
|
|
argv = append(argv, in.Args()...)
|
|
return runAppBinary(ctx, argv, out)
|
|
},
|
|
}
|
|
}
|
|
|
|
func runAppBinary(ctx context.Context, argv []string, out bonfire.Output) error {
|
|
if len(argv) == 0 {
|
|
return fmt.Errorf("summer: missing app command")
|
|
}
|
|
dir, err := os.Getwd()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
appDir, err := build.FindAppDir(dir)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
m, err := build.LoadManifest(filepath.Join(appDir, "summer.yaml"))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
bin := filepath.Join(appDir, "bin", m.Binary)
|
|
if _, err := os.Stat(bin); err != nil {
|
|
if err := build.App(ctx, appDir, out); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
self, err := os.Executable()
|
|
if err == nil {
|
|
if same, _ := sameFile(self, bin); same {
|
|
return fmt.Errorf("summer: refusing to recurse into %s", bin)
|
|
}
|
|
}
|
|
cmd := exec.CommandContext(ctx, bin, argv...)
|
|
cmd.Dir = appDir
|
|
cmd.Stdout = out
|
|
cmd.Stderr = out
|
|
cmd.Stdin = os.Stdin
|
|
cmd.Env = os.Environ()
|
|
if err := cmd.Run(); err != nil {
|
|
return fmt.Errorf("summer: %s: %w", strings.Join(argv, " "), err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func sameFile(a, b string) (bool, error) {
|
|
ai, err := os.Stat(a)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
bi, err := os.Stat(b)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return os.SameFile(ai, bi), nil
|
|
}
|