When to Use the redis_task_queue Flutter Package
The redis_task_queue Flutter package is a lightweight, Redis‑backed task queue designed for server‑side Dart. It shines when you need to:
- Offload work from the UI thread to a background worker.
- Schedule jobs for later execution or retry failed jobs automatically.
- Maintain a dead‑letter list for jobs that exceed retry limits.
- Implement weighted queues to prioritize critical tasks.
Because the package talks directly to a Redis instance, it is best suited for apps that already use Redis for caching, session storage, or pub/sub. If your Flutter project runs on mobile devices without a Redis server, consider using a cloud function or a backend service that hosts the queue.
Installation
Add the package to your pubspec.yaml with the official Flutter command:
flutter pub add redis_task_queueAfter the command completes, run flutter pub get to fetch the dependency.
Basic Setup and Configuration
Before you can enqueue or process jobs, you need a running Redis server and the connection details (host, port, optional password). Store these values securely, for example in .env files or using the flutter_dotenv package.
Tip: Keep the Redis connection logic inside a dedicated service class. This isolates third‑party code and makes unit testing easier.
Creating a Queue Service
import 'package:redis_task_queue/redis_task_queue.dart';
import 'package:dotenv/dotenv.dart' show load, env;
class QueueService {
late final RedisTaskQueue _queue;
QueueService() {
// Load environment variables (ensure you call load() early in main())
final host = env['REDIS_HOST'] ?? '127.0.0.1';
final port = int.tryParse(env['REDIS_PORT'] ?? '6379') ?? 6379;
final password = env['REDIS_PASSWORD'];
// Initialise the Redis client used by the package
final client = RedisTaskQueueClient(
host: host,
port: port,
password: password,
);
// Create a named queue; you can have multiple queues for different priorities
_queue = RedisTaskQueue(client: client, queueName: 'flutter_jobs');
}
Future enqueueJob(String taskName, Map payload) async {
await _queue.enqueue(taskName, payload);
}
// Example of scheduling a job 5 minutes from now
Future scheduleJob(String taskName, Map payload) async {
final scheduleTime = DateTime.now().add(Duration(minutes: 5));
await _queue.schedule(taskName, payload, scheduleTime);
}
}The above service wraps the core API and can be injected wherever you need to enqueue work (e.g., from a Bloc, Provider, or Riverpod provider).
Processing Jobs with a Worker
In a production setup you typically run a separate Dart process (or a server‑side isolate) that continuously pulls jobs from the queue and executes them. Below is a minimal worker implementation that you can run on a server or in a background isolate.
import 'package:redis_task_queue/redis_task_queue.dart';
import 'dart:async';
Future main() async {
// Re‑use the same connection configuration as the QueueService
final client = RedisTaskQueueClient(host: '127.0.0.1', port: 6379);
final worker = RedisTaskQueueWorker(
client: client,
queueName: 'flutter_jobs',
// Define how many jobs to fetch in one batch (optional)
batchSize: 10,
// Optional: maximum number of retries before moving to dead‑letter list
maxRetries: 3,
// Provide a handler that knows how to process each task type
handler: (String taskName, Map payload) async {
switch (taskName) {
case 'sendEmail':
await _sendEmail(payload);
break;
case 'generateReport':
await _generateReport(payload);
break;
default:
print('Unknown task: $taskName');
}
},
);
// Start the infinite processing loop
await worker.start();
}
Future _sendEmail(Map data) async {
// Placeholder implementation – replace with real email logic
print('Sending email to ${data['to']} with subject ${data['subject']}');
}
Future _generateReport(Map data) async {
// Placeholder implementation – replace with real report generation
print('Generating report for user ${data['userId']}');
}The RedisTaskQueueWorker handles retries, moves failed jobs to a dead‑letter list, and respects the queue's weighting if you configure multiple queues.
Common Mistakes to Avoid
- Running the worker on the UI thread. The worker blocks while waiting for jobs. Always run it in a separate isolate, server process, or background service.
- Hard‑coding Redis credentials. Store them securely and never commit them to version control.
- Ignoring serialization errors. The package stores payloads as JSON. Ensure your data structures are JSON‑serializable.
- Assuming the package works on the client‑only side. It is intended for server‑side Dart. If you need a pure client solution, look for a different queue strategy.
Testing the Integration
Because the queue interacts with an external Redis instance, write integration tests that spin up a temporary Redis container (e.g., using Docker) and verify enqueue/dequeue behavior. Mocking the RedisTaskQueueClient is also possible for unit tests.
FAQ
- Q: Can I use redis_task_queue directly in a mobile Flutter app?
A: Technically you can, but the package expects a persistent Redis connection. Mobile networks are unreliable, and embedding a Redis server in a mobile app is impractical. The recommended pattern is to call a backend API that enqueues jobs on your behalf.
- Q: How do I monitor the dead‑letter list?
A: The package provides a
deadLetterQueueaccessor. You can query it withawait _queue.deadLetterQueue.getAll()or use Redis CLI commands likeLRANGE dead_letter:flutter_jobs 0 -1. - Q: Does the package support job prioritization?
A: Yes, you can create multiple queues with different names and assign weights when pulling jobs. The worker can be configured with a
queueWeightsmap to prioritize certain queues. - Q: What happens if the Redis server goes down?
A: Enqueue calls will throw a connection error. It is advisable to wrap calls in
try/catchand implement exponential back‑off or fallback logic.
Next Steps
After you have a stable worker running, consider adding:
- Metrics collection (e.g., job latency, success/failure counts).
- Graceful shutdown handling for the worker process.
- Integration with your existing logging and monitoring stack.
For the most up‑to‑date API surface, always refer to the official package page on pub.dev.
Frequently Asked Questions
Can I use redis_task_queue directly in a mobile Flutter app?
Technically you can, but the package expects a persistent Redis connection. Mobile networks are unreliable, and embedding a Redis server in a mobile app is impractical. The recommended pattern is to call a backend API that enqueues jobs on your behalf.
How do I monitor the dead‑letter list?
The package provides a deadLetterQueue accessor. You can query it with await _queue.deadLetterQueue.getAll() or use Redis CLI commands like LRANGE dead_letter:your_queue 0 -1.
Does the package support job prioritization?
Yes, you can create multiple queues with different names and assign weights when pulling jobs. The worker can be configured with a queueWeights map to prioritize certain queues.
What happens if the Redis server goes down?
Enqueue calls will throw a connection error. Wrap calls in try/catch and implement exponential back‑off or fallback logic to handle temporary outages.