feat: Artisan checklist for application commands, hints and coverage gate
- migrate, migrate:rollback and deferred:purge gain --pretend and --force; they and queue:clear confirm only in production on an interactive terminal, so deploys over SSH proceed as before - result lines: Applied N migrations, Rolled back <id> of <plugin>, Cleared N jobs from <queue> - --json for migrate:status, key:generate, route:list, admin:token:create, admin:token:list, admin:token:scopes and websockets:health; -q keeps the key and the token - hints for an empty DSN, an unreachable database, an invalid app.key, a missing uploads bucket and an application binary run below its root - flare and websockets:health return bonfire.Reported after printing - long help and examples for every application command, greeter:hello and blog:publish; cmd/summer TestCommandsDocumented fails on any gap
This commit is contained in:
@@ -226,7 +226,7 @@ queues:
|
||||
|---------|---------------------|-------------|
|
||||
| `queue:work` | `--queue <name>`, repeatable | Runs a job worker in the foreground on the named queues (default: every known queue) until SIGINT or SIGTERM. It prints a startup summary on a terminal (environment, queues with their concurrency, database host, whether the `scheduled` queue runs here) and logs it as a `startup summary` record of component `queue` otherwise. On a signal it stops the worker within 10 seconds, prints and logs a `shutdown report` (jobs done, failed and handed back to the queue, uptime, stop errors) and exits 0, or 1 when the worker fails to stop. An unknown queue is an error that lists the known ones. |
|
||||
| `schedule:run` | `--once` (bare) | Without `--once`: runs a worker on the `scheduled` queue that carries every plugin's periodic jobs, prints a startup summary (entry count and the next due entry; a `startup summary` record of component `schedule` off a terminal) and runs until SIGINT or SIGTERM, then stops within 10 seconds, prints a shutdown report (scheduled commands run and failed, uptime) and exits 0. With `--once`: runs, in-process and without River, every entry due in the current minute of `app.timezone` (a daily entry at its hour and minute; `Every(d)` of a minute or less on every run, a longer one when the minutes since midnight are a multiple of `d`), printing `Running scheduled command: <command> <args>` per entry or `No scheduled commands are ready to run.`. An unregistered command prints a warning and is skipped. It ends with `Ran N due entries (M failed)`; the exit status is the first command error, after every due entry ran. There is no overlap lock: two runs in one minute run the due entries twice, as Laravel does. System cron: `* * * * * cd /app && ./bin/app schedule:run --once`. |
|
||||
| `queue:clear` | `[queue]` (default `default`) | Deletes the available, scheduled and retryable jobs of one queue in batches until none are left and prints `Cleared N jobs`. Running jobs are never touched. |
|
||||
| `queue:clear` | `[queue]` (default `default`), `--force` | Deletes the available, scheduled and retryable jobs of one queue in batches until none are left and prints `Cleared N jobs from <queue>`. Running jobs are never touched. In production on an interactive terminal it asks first; `--force` skips the question, and off a terminal it never asks. |
|
||||
|
||||
## Dependencies
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package conga
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
@@ -95,17 +96,33 @@ scheduled queue.`,
|
||||
},
|
||||
{
|
||||
Name: "queue:clear",
|
||||
Description: "Clear all queued jobs, by deleting all pending jobs.",
|
||||
Description: "Clear pending jobs from a queue",
|
||||
Long: `Deletes the available, scheduled and retryable jobs of one queue (default
|
||||
"default") in batches until none are left, and prints how many it deleted.
|
||||
Running jobs are never touched. In production, on an interactive terminal, it
|
||||
asks first; --force skips the question. Off a terminal it never asks.`,
|
||||
Args: []bonfire.Arg{{
|
||||
Name: "queue",
|
||||
Description: "The name of the queue to clear (default \"default\")",
|
||||
}},
|
||||
Flags: []bonfire.Flag{{
|
||||
Name: "force",
|
||||
Description: "Skip the confirmation asked in production on a terminal",
|
||||
Bare: true,
|
||||
}},
|
||||
Examples: []bonfire.Example{
|
||||
{Command: "queue:clear", Description: "Clear the default queue"},
|
||||
{Command: "queue:clear imports --force", Description: "Clear the imports queue without the production question"},
|
||||
},
|
||||
Run: func(ctx context.Context, in bonfire.Input, out bonfire.Output) error {
|
||||
queue, _ := in.Argument("queue")
|
||||
queue = strings.TrimSpace(queue)
|
||||
if queue == "" {
|
||||
queue = defaultQueue
|
||||
}
|
||||
if err := confirmProduction(app, in, out, fmt.Sprintf("Delete every pending job of queue %q in production?", queue)); err != nil {
|
||||
return err
|
||||
}
|
||||
return withDB(ctx, app, func() error {
|
||||
return clearQueue(ctx, app, queue, out)
|
||||
})
|
||||
@@ -356,7 +373,33 @@ func clearQueue(ctx context.Context, app *backpack.App, queue string, out bonfir
|
||||
}
|
||||
total += len(res.Jobs)
|
||||
}
|
||||
out.Info(fmt.Sprintf("Cleared %d jobs", total))
|
||||
out.Success(fmt.Sprintf("Cleared %d jobs from %s", total, queue))
|
||||
return nil
|
||||
}
|
||||
|
||||
// confirmProduction asks question before a destructive step when the
|
||||
// environment is production and out is an interactive terminal, unless
|
||||
// --force is set (D-28). Off a terminal, under -n or -q and in
|
||||
// bonfire.Call it never asks. A "no" returns a Reported error (exit 1).
|
||||
func confirmProduction(app *backpack.App, in bonfire.Input, out bonfire.Output, question string) error {
|
||||
if in != nil {
|
||||
if v, ok := in.Flag("force"); ok {
|
||||
if force, _ := strconv.ParseBool(v); force {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
if app == nil || app.Config == nil || app.Config.Environment() != "production" {
|
||||
return nil
|
||||
}
|
||||
ok, err := bonfire.ConfirmProceed(out, question)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !ok {
|
||||
out.Warning("Cancelled.")
|
||||
return bonfire.Reported(errors.New("queue:clear cancelled"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user