feat(11-02): run plugin schedules as River periodic jobs through bonfire.Call
- pact.HasSchedule with ScheduledCommand and Daily/DailyAt/Every cadences (no River import) - bonfire.Call, Catalog and ErrUnknownCommand for in-process command runs - conga Daily/Every wall-clock schedules in app.timezone, periodic jobs on every worker, scheduled queue (MaxAttempts 1, unique by args within the cadence period) - scheduled worker runs only entries matching the compiled table; unregistered commands are skipped with a Warn log - generated app main publishes bonfire.NewCatalog(commands); hello main regenerated
This commit is contained in:
72
modules/bonfire/call.go
Normal file
72
modules/bonfire/call.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package bonfire
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ErrUnknownCommand is returned by Call when no command has the given name.
|
||||
var ErrUnknownCommand = errors.New("bonfire: unknown command")
|
||||
|
||||
// Call runs the command named name in-process with args, writing its output
|
||||
// to out. Stdin is empty, so prompts take their defaults. A name that no
|
||||
// command has is ErrUnknownCommand.
|
||||
func Call(ctx context.Context, commands []Command, name string, args []string, out io.Writer) error {
|
||||
cmd, ok := findCommand(commands, name)
|
||||
if !ok {
|
||||
return fmt.Errorf("%w: %q", ErrUnknownCommand, name)
|
||||
}
|
||||
if out == nil {
|
||||
out = io.Discard
|
||||
}
|
||||
root, err := NewRootIO(name, []Command{cmd}, strings.NewReader(""), out, out)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
root.SetArgs(append([]string{name}, args...))
|
||||
if ctx == nil {
|
||||
ctx = context.Background()
|
||||
}
|
||||
return root.ExecuteContext(ctx)
|
||||
}
|
||||
|
||||
// Catalog is the final command list of an application binary. The generated
|
||||
// main publishes it on the app so code outside the cobra root, such as the
|
||||
// scheduler, can run any registered command with Call.
|
||||
type Catalog struct {
|
||||
commands []Command
|
||||
}
|
||||
|
||||
// NewCatalog returns a Catalog holding a copy of commands.
|
||||
func NewCatalog(commands []Command) *Catalog {
|
||||
return &Catalog{commands: append([]Command(nil), commands...)}
|
||||
}
|
||||
|
||||
// Has reports whether the catalog holds a command named name.
|
||||
func (c *Catalog) Has(name string) bool {
|
||||
if c == nil {
|
||||
return false
|
||||
}
|
||||
_, ok := findCommand(c.commands, name)
|
||||
return ok
|
||||
}
|
||||
|
||||
// Call runs the named catalog command in-process; see the package Call.
|
||||
func (c *Catalog) Call(ctx context.Context, name string, args []string, out io.Writer) error {
|
||||
if c == nil {
|
||||
return fmt.Errorf("%w: %q", ErrUnknownCommand, name)
|
||||
}
|
||||
return Call(ctx, c.commands, name, args, out)
|
||||
}
|
||||
|
||||
func findCommand(commands []Command, name string) (Command, bool) {
|
||||
for _, c := range commands {
|
||||
if c.Name == name {
|
||||
return c, true
|
||||
}
|
||||
}
|
||||
return Command{}, false
|
||||
}
|
||||
Reference in New Issue
Block a user