Skip to content

CLI tools

gisila_queue ships two kinds of command-line support: helpers for your own bin/worker.dart and bin/beat.dart (your tasks must be compiled into the binary), and two bundled binaries that don’t need your tasks (gisila_queue inspect|purge and rose).

The helpers live in a separate library:

import 'package:gisila_queue/gisila_queue.dart';
import 'package:gisila_queue/gisila_queue_cli.dart';

All CLIs are Redis-only and share these flags:

Flag Default Description
--redis-url=URL REDIS_URL env var redis:// or rediss:// URL with credentials and database. Prefer the env var to keep passwords out of the process list.
--redis-host=H / --redis-port=P localhost / 6379 Used when no URL is given.
--namespace=NS (alias --prefix) gq Must match producers, workers, beat and Rose of the app.

Flags are --name or --name=value; anything else is ignored.

Parses worker flags, builds a Redis-backed app, runs a worker with graceful shutdown.

class WorkerCli {
factory WorkerCli.parse(List<String> argv);
static const usage = '...';
bool get help;
GisilaQueue buildApp();
Future<void> run(GisilaQueue app);
final String redisHost;
final int redisPort;
final RedisOptions redisOptions;
final String prefix;
final List<String> queues;
final int concurrency;
final LogLevel logLevel;
final Duration drainTimeout;
}

When to use: as the whole body of a Redis worker entrypoint. Build the app by hand instead when you need RabbitMQ, events, a router, or other non-default options (you can still read the parsed fields and call installShutdownHooks).

Flag Field Default
--queues=a,b queues ['default']
--concurrency=N concurrency 1
--loglevel=debug|info|warning|error logLevel info
--drain-timeout=SECONDS drainTimeout 30 s
--help, -h help

buildApp() returns a GisilaQueue with RedisBroker, RedisResultBackend, RedisControlChannel and a ConsoleQueueLogger at logLevel, all under prefix. No event sink and no router. run(app) builds app.worker(queues:, concurrency:), installs SIGINT/SIGTERM handlers that call worker.stop(timeout: drainTimeout), prints a banner, waits, then closes the app.

bin/worker.dart
import 'package:gisila_queue/gisila_queue_cli.dart';
import 'package:my_app/tasks.dart'; // your registerTasks(GisilaQueue app)
Future<void> main(List<String> argv) async {
final cli = WorkerCli.parse(argv);
if (cli.help) return print(WorkerCli.usage);
final app = cli.buildApp();
registerTasks(app);
await cli.run(app);
}
Terminal window
REDIS_URL=redis://:secret@localhost:6379/0 \
dart run bin/worker.dart --namespace=shop --queues=default,emails --concurrency=8

Parses beat flags and builds a beat with a Redis lock and state store.

class BeatCli {
factory BeatCli.parse(List<String> argv);
static const usage = '...';
bool get help;
GisilaQueue buildApp();
Beat buildBeat(GisilaQueue app);
Future<void> run(Beat beat);
final Duration tickInterval;
final Duration lockTtl;
// plus redisHost, redisPort, redisOptions, prefix, logLevel
}

When to use: as the body of bin/beat.dart. Running two copies is safe: the second waits on the lock.

Flag Field Default
--tick-interval=SECONDS tickInterval 1 s
--lock-ttl=SECONDS lockTtl 30 s
--loglevel=... logLevel info

buildApp() builds a broker and result backend (no control channel). buildBeat(app) returns a Beat with RedisBeatLock and RedisBeatStateStore. run(beat) installs signal handlers that call beat.stop(), runs, then closes the app.

bin/beat.dart
import 'package:gisila_queue/gisila_queue.dart';
import 'package:gisila_queue/gisila_queue_cli.dart';
Future<void> main(List<String> argv) async {
final cli = BeatCli.parse(argv);
if (cli.help) return print(BeatCli.usage);
final app = cli.buildApp();
final beat = cli.buildBeat(app)
..schedule('cleanup', 'tasks.cleanup', Schedule.every(const Duration(minutes: 5)));
await cli.run(beat);
}

The flag parser all binaries share.

class CliArgs {
CliArgs(Map<String, String> values);
factory CliArgs.parse(List<String> argv);
bool has(String key);
String? string(String key);
String stringOr(String key, String fallback);
int intOr(String key, int fallback);
List<String>? stringList(String key);
({String host, int port, RedisOptions options}) redisTarget();
}

When to use: add your own flags to a custom entrypoint and parse Redis settings the same way as the bundled tools. --flag without a value is stored as 'true'. stringList splits on commas and trims. redisTarget() reads --redis-url, then REDIS_URL, then --redis-host/--redis-port.

void installShutdownHooks(Future<void> Function() onShutdown)

Calls onShutdown once on the first SIGINT or SIGTERM (SIGTERM is skipped on Windows), then cancels its signal watchers so the process can exit.

final worker = app.worker(queues: ['default']);
installShutdownHooks(() async {
await worker.stop(timeout: const Duration(seconds: 30));
});
await worker.run();
await app.close();

celery inspect / celery purge analogue on a RedisBroker.

Terminal window
dart run gisila_queue:gisila_queue inspect --namespace=shop --queues=default,emails,dead_letter
dart run gisila_queue:gisila_queue purge --namespace=shop --queue=default
Command Effect
inspect [--queues=a,b] Prints ready messages per queue (default default) and the total unacked count.
purge --queue=NAME Deletes the ready messages on one queue. Delayed messages stay.

Exits with code 64 on missing or unknown arguments.

Runs GisilaRose against Redis. Declared as a package executable.

Terminal window
dart run gisila_queue:rose --namespace=shop --port=5555 --basic-auth=admin:secret
Flag Default Description
--host=HOST 127.0.0.1 Bind address. Non-loopback needs --basic-auth while write actions are enabled.
--port=PORT 5555 HTTP port.
--basic-auth=user:pass HTTP Basic Auth on every route.
--no-queues No broker or backend: no depths, fire or retry.
--no-control No control channel: no revoke, pause, resume.
--allow-unauthenticated Serve write actions on a non-loopback host without auth.

See also: Run workers, Deploy workers.