Skip to content

Monitor your queues

You’ll turn on lifecycle events, run the GisilaRose dashboard to watch tasks and workers live, and forward failures to your own alerting.

  • Producers and workers on Redis.

Events are off by default. With GisilaQueue.redis, pass events: true in producers and workers:

import 'package:gisila_queue/gisila_queue.dart';
final app = GisilaQueue.redis(namespace: 'shop', events: true);

When building components by hand, add events: RedisEventSink(prefix: 'shop'). WorkerCli.buildApp() does not add an event sink, so build the worker app yourself (see Run workers).

Terminal window
REDIS_URL=redis://:secret@localhost:6379/0 \
dart run gisila_queue:rose --namespace=shop --port=5555

Open http://localhost:5555. You see recent tasks with state, args, result and timings, workers with their counters and heartbeats, queue depths, and per-task-name stats. Fire, retry, revoke, pause and resume are available because the binary opens a broker and a control channel.

To expose it beyond localhost, require auth:

Terminal window
dart run gisila_queue:rose --namespace=shop --host=0.0.0.0 --basic-auth=admin:long-random-password

Rose refuses a public bind with write actions and no auth. --no-queues --no-control makes it read-only.

Terminal window
curl -u admin:pw localhost:5555/api/stats
curl -u admin:pw 'localhost:5555/api/tasks?state=failure&limit=20'
curl -u admin:pw -X POST -H 'Content-Type: application/json' \
-d '{"name":"health.ping"}' localhost:5555/api/tasks/fire
curl -u admin:pw -X POST -H 'Content-Type: application/json' localhost:5555/api/queues/emails/pause

All POSTs need Content-Type: application/json. See the HTTP API table.

Terminal window
dart run gisila_queue:gisila_queue inspect --namespace=shop --queues=default,emails,dead_letter

Alert when dead_letter grows or a queue’s depth keeps rising.

Implement QueueEventSink and combine it with the Redis sink:

class AlertSink implements QueueEventSink {
@override
Future<void> emit(QueueEvent event) async {
if (event.type != QueueEventType.taskFailed) return;
try {
await alerts.send('${event.taskName} ${event.taskId}: ${event.fields['error']}');
} catch (_) {
// never throw from a sink
}
}
@override
Future<void> close() async {}
}
final app = GisilaQueue(
broker: RedisBroker(prefix: 'shop'),
backend: RedisResultBackend(prefix: 'shop'),
events: MultiEventSink([RedisEventSink(prefix: 'shop'), AlertSink()]),
);

Or read the stream from a separate process with RedisEventSource(prefix: 'shop').events().

Enqueue a task and watch it appear in Rose as pending, then started, then success. Stop a worker and its status turns not alive about 30 seconds after its last heartbeat.