bg_orchestrator 1.1.0 copy "bg_orchestrator: ^1.1.0" to clipboard
bg_orchestrator: ^1.1.0 copied to clipboard

Production-grade background task orchestrator for Flutter with task chaining, timeouts, cron scheduling, batching, encryption, and persistent services.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:bg_orchestrator/taskflow.dart';

// ===== MIDDLEWARE (Interceptors) =====
class LoggingMiddleware extends TaskMiddleware {
  @override
  Future<TaskResult> execute(String taskName, TaskContext ctx,
      Future<TaskResult> Function() next) async {
    print('📋 [MIDDLEWARE] Task "$taskName" started');
    final startTime = DateTime.now();
    final result = await next();
    final duration = DateTime.now().difference(startTime);
    print('✅ [MIDDLEWARE] Task "$taskName" completed in ${duration.inMilliseconds}ms');
    return result;
  }
}

// Entry point
void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // ==================== COMPREHENSIVE EXAMPLE APP ====================
  // Demonstrates ALL v1.0.4 features:
  // ✅ Task enqueueing with timeout, middleware, dedup, concurrency, rate limiting, priority queues, encryption
  // ✅ Task chaining with sequential execution
  // ✅ Periodic scheduling with cron expressions and time windows
  // ✅ Persistent services with foreground notification
  // ✅ Task monitoring with real-time progress
  // ✅ Execution history and logging
  // ✅ Lifecycle hooks (onTaskStart, onTaskComplete, onTaskFailed, onChainComplete)

  // ===== TASK HANDLERS =====
  TaskFlow.registerHandler('syncRideHistory', (ctx) async {
    final rideId = ctx.input['rideId'] as String? ?? 'ride_123';
    print('📊 Syncing ride history for $rideId...');
    await Future.delayed(Duration(seconds: 2));
    await ctx.reportProgress(0.5);
    await Future.delayed(Duration(seconds: 2));
    await ctx.reportProgress(1.0);
    return TaskResult.success(data: {
      'synced': true,
      'rideId': rideId,
      'timestamp': DateTime.now().toString(),
    });
  });

  TaskFlow.registerHandler('updateLocation', (ctx) async {
    final latitude = (ctx.input['lat'] as num?)?.toDouble() ?? 12.9716;
    final longitude = (ctx.input['lng'] as num?)?.toDouble() ?? 77.5946;
    print('📍 GPS Update: ($latitude, $longitude)');
    await Future.delayed(Duration(milliseconds: 500));
    return TaskResult.success(data: {
      'lat': latitude,
      'lng': longitude,
      'timestamp': DateTime.now().toString(),
    });
  });

  TaskFlow.registerHandler('processPayment', (ctx) async {
    final amount = ctx.input['amount'] as num? ?? 250.0;
    print('💳 Processing payment: ₹$amount...');
    await Future.delayed(Duration(seconds: 1));
    await ctx.reportProgress(0.5);
    print('💳 Verifying with payment gateway...');
    await Future.delayed(Duration(seconds: 1));
    await ctx.reportProgress(1.0);
    return TaskResult.success(data: {
      'transactionId': 'TXN_${DateTime.now().millisecondsSinceEpoch}',
      'amount': amount,
      'status': 'completed',
    });
  });

  TaskFlow.registerHandler('exampleTask', (ctx) async {
    await Future.delayed(Duration(seconds: 1));
    await ctx.reportProgress(0.5);
    await Future.delayed(Duration(seconds: 1));
    await ctx.reportProgress(1.0);
    return TaskResult.success(data: {'result': 'Done!'});
  });

  TaskFlow.registerHandler('failingTask', (ctx) async {
    await Future.delayed(Duration(milliseconds: 500));
    return TaskResult.failure(message: 'Task failed intentionally');
  });

  TaskFlow.registerHandler('delayedTask', (ctx) async {
    final seconds = ctx.input['seconds'] as int? ?? 3;
    for (int i = 0; i < seconds; i++) {
      await ctx.reportProgress((i + 1) / seconds);
      await Future.delayed(Duration(seconds: 1));
    }
    return TaskResult.success();
  });

  TaskFlow.registerHandler('validatePayment', (ctx) async {
    print('🔐 Validating payment...');
    await Future.delayed(Duration(seconds: 1));
    return TaskResult.success(data: {
      'validated': true,
      'amount': ctx.input['amount'] ?? 0,
    });
  });

  TaskFlow.registerHandler('sendConfirmation', (ctx) async {
    print('📧 Sending confirmation email...');
    await Future.delayed(Duration(seconds: 1));
    return TaskResult.success(data: {
      'email_sent': true,
      'recipient': 'user@example.com',
      'timestamp': DateTime.now().toString(),
    });
  });

  TaskFlow.registerHandler('periodicSync', (ctx) async {
    print('🔄 Periodic sync running...');
    await Future.delayed(Duration(seconds: 2));
    return TaskResult.success(data: {
      'synced_items': 42,
      'last_sync': DateTime.now().toString(),
    });
  });

  // Batch handler for uploading photos
  TaskFlow.registerHandler('uploadPhotos', (ctx) async {
    final filename = ctx.input['filename'] as String? ?? 'photo.jpg';
    print('📸 Uploading $filename...');
    await Future.delayed(Duration(milliseconds: 500));
    return TaskResult.success(data: {'url': 'https://cloud.example.com/$filename'});
  });

  // Register middleware
  TaskFlow.use(LoggingMiddleware());

  // ===== LIFECYCLE HOOKS =====
  TaskHooks.onTaskStart((entry) {
    print('🚀 [HOOK] Task started: ${entry.taskName} (${entry.executionId})');
  });

  TaskHooks.onTaskComplete((entry) {
    print('✅ [HOOK] Task completed: ${entry.taskName} in ${entry.durationMs}ms');
  });

  TaskHooks.onTaskFailed((entry) {
    print('🔥 [HOOK] Task failed: ${entry.taskName} - ${entry.error}');
  });

  TaskHooks.onChainComplete((chainId, status) {
    print('⛓️ [HOOK] Chain completed: $chainId - Status: $status');
  });

  await TaskFlow.initialize();
  runApp(const TaskFlowExampleApp());
}

class TaskFlowExampleApp extends StatelessWidget {
  const TaskFlowExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'bg_orchestrator Demo',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const ExampleHome(),
    );
  }
}

class ExampleHome extends StatefulWidget {
  const ExampleHome({super.key});

  @override
  State<ExampleHome> createState() => _ExampleHomeState();
}

class _ExampleHomeState extends State<ExampleHome> {
  String? _executionId;
  TaskStatus? _currentStatus;
  Map<String, dynamic>? _taskResult;
  final List<String> _activityLog = [];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('bg_orchestrator: Full Feature Demo'),
        elevation: 0,
      ),
      body: SingleChildScrollView(
        child: Padding(
          padding: const EdgeInsets.all(16),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              const Text(
                '🚀 Production-Grade Background Task Orchestrator',
                style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
              ),
              const SizedBox(height: 8),
              const Text(
                'All v1.0.0-v1.0.4 features: Timeouts • Middleware • History • Hooks • Cron • Time Windows • Dedup • Batching • Concurrency • Rate Limiting • Priority Queues • Encryption',
                style: TextStyle(fontSize: 11, color: Colors.grey),
              ),
              const SizedBox(height: 24),

              // ===== CORE FEATURES =====
              _buildSection(
                title: '1️⃣ Core Task Execution',
                children: [
                  _buildButton(
                    label: 'Enqueue: Simple Task',
                    onPressed: () => _enqueueSimple(),
                  ),
                  _buildButton(
                    label: 'Enqueue: With Timeout (Soft/Hard)',
                    onPressed: () => _enqueueWithTimeout(),
                  ),
                  _buildButton(
                    label: 'Enqueue: With Deduplication',
                    onPressed: () => _enqueueWithDedup(),
                  ),
                ],
              ),
              const SizedBox(height: 16),

              // ===== ADVANCED FEATURES =====
              _buildSection(
                title: '2️⃣ Advanced Scheduling',
                children: [
                  _buildButton(
                    label: 'Schedule: Periodic (30 min)',
                    onPressed: () => _enqueueSchedule(),
                  ),
                  _buildButton(
                    label: 'Schedule: Cron (Daily 9am)',
                    onPressed: () => _enqueueCron(),
                  ),
                  _buildButton(
                    label: 'Schedule: Time Window (Off-Peak)',
                    onPressed: () => _enqueueWithWindow(),
                  ),
                ],
              ),
              const SizedBox(height: 16),

              // ===== BUSINESS LOGIC =====
              _buildSection(
                title: '3️⃣ Task Chaining',
                children: [
                  _buildButton(
                    label: 'Chain: Validate → Process → Send',
                    onPressed: () => _enqueueChain(),
                  ),
                  _buildButton(
                    label: 'Chain: With Constraints & Retry',
                    onPressed: () => _enqueueChainAdvanced(),
                  ),
                ],
              ),
              const SizedBox(height: 16),

              // ===== CONCURRENCY & RATE LIMITING =====
              _buildSection(
                title: '4️⃣ Concurrency & Rate Limiting',
                children: [
                  _buildButton(
                    label: 'Enqueue: Limited Concurrency',
                    onPressed: () => _enqueueWithConcurrency(),
                  ),
                  _buildButton(
                    label: 'Enqueue: Rate Limited (10/min)',
                    onPressed: () => _enqueueWithRateLimit(),
                  ),
                ],
              ),
              const SizedBox(height: 16),

              // ===== PRIORITY QUEUES =====
              _buildSection(
                title: '5️⃣ Priority Queues',
                children: [
                  _buildButton(
                    label: 'Queue: Critical (100x weight)',
                    onPressed: () => _enqueueCriticalQueue(),
                  ),
                  _buildButton(
                    label: 'Queue: Low (0.1x weight)',
                    onPressed: () => _enqueueLowQueue(),
                  ),
                ],
              ),
              const SizedBox(height: 16),

              // ===== SECURITY & ENCRYPTION =====
              _buildSection(
                title: '6️⃣ Security & Encryption',
                children: [
                  _buildButton(
                    label: 'Enqueue: AES-256 Encrypted',
                    onPressed: () => _enqueueEncrypted(),
                  ),
                  _buildButton(
                    label: 'Process Payment (Sensitive Data)',
                    onPressed: () => _enqueuePaymentSecure(),
                  ),
                ],
              ),
              const SizedBox(height: 16),

              // ===== PERSISTENT SERVICES =====
              _buildSection(
                title: '7️⃣ Persistent Services',
                children: [
                  _buildButton(
                    label: 'Start: Live GPS Tracking',
                    onPressed: () => _startPersistentService(),
                  ),
                  _buildButton(
                    label: 'Stop: Foreground Service',
                    onPressed: () => _stopPersistentService(),
                  ),
                ],
              ),
              const SizedBox(height: 16),

              // ===== BATCH OPERATIONS =====
              _buildSection(
                title: '8️⃣ Batch Operations',
                children: [
                  _buildButton(
                    label: 'Batch: Upload 5 Photos',
                    onPressed: () => _enqueueBatch(),
                  ),
                  _buildButton(
                    label: 'Batch: Process 10 Items',
                    onPressed: () => _enqueueBatchLarge(),
                  ),
                ],
              ),
              const SizedBox(height: 16),

              // ===== ADVANCED: MIDDLEWARE & HOOKS =====
              _buildSection(
                title: '9️⃣ Middleware & Lifecycle Hooks',
                children: [
                  _buildButton(
                    label: 'Task with Middleware (Check Console)',
                    onPressed: () => _enqueueWithMiddleware(),
                  ),
                  _buildButton(
                    label: 'View Task History',
                    onPressed: () => _viewTaskHistory(),
                  ),
                ],
              ),
              const SizedBox(height: 16),

              // ===== ADVANCED: SERVICE COMMUNICATION =====
              _buildSection(
                title: '🔟 Service Communication',
                children: [
                  _buildButton(
                    label: 'Send Location to Service',
                    onPressed: () => _sendLocationToService(),
                  ),
                  _buildButton(
                    label: 'Listen for Service Events',
                    onPressed: () => _listenServiceEvents(),
                  ),
                ],
              ),

              const SizedBox(height: 24),
              const Divider(),
              const SizedBox(height: 16),

              // ===== RESULTS PANEL =====
              if (_executionId != null) ...[
                Container(
                  padding: const EdgeInsets.all(12),
                  decoration: BoxDecoration(
                    color: Colors.blue[50],
                    border: Border.all(color: Colors.blue),
                    borderRadius: BorderRadius.circular(8),
                  ),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Row(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        children: [
                          const Text(
                            'Task Status & Results',
                            style: TextStyle(fontWeight: FontWeight.bold, fontSize: 14),
                          ),
                          Chip(
                            label: Text(_statusString(_currentStatus)),
                            backgroundColor: _statusColor(_currentStatus).withValues(alpha: 0.3),
                            labelStyle: TextStyle(
                              color: _statusColor(_currentStatus),
                              fontWeight: FontWeight.bold,
                            ),
                          ),
                        ],
                      ),
                      const SizedBox(height: 8),
                      Text(
                        'ID: $_executionId',
                        style: const TextStyle(fontSize: 11, color: Colors.grey),
                      ),
                      const SizedBox(height: 8),

                      // Progress bar
                      if (_currentStatus is TaskRunning)
                        Column(
                          children: [
                            LinearProgressIndicator(
                              value: (_currentStatus as TaskRunning).progress,
                              minHeight: 8,
                            ),
                            const SizedBox(height: 4),
                            Text(
                              'Progress: ${((_currentStatus as TaskRunning).progress * 100).toStringAsFixed(0)}%',
                              style: const TextStyle(fontSize: 12),
                            ),
                            const SizedBox(height: 8),
                          ],
                        ),

                      // Task result display
                      if (_taskResult != null)
                        Container(
                          padding: const EdgeInsets.all(8),
                          decoration: BoxDecoration(
                            color: Colors.white,
                            borderRadius: BorderRadius.circular(4),
                            border: Border.all(color: Colors.green, width: 2),
                          ),
                          child: Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              const Text(
                                '✅ Task Result:',
                                style: TextStyle(fontWeight: FontWeight.bold, color: Colors.green),
                              ),
                              const SizedBox(height: 8),
                              ..._taskResult!.entries.map((e) => Padding(
                                padding: const EdgeInsets.symmetric(vertical: 4),
                                child: Row(
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  children: [
                                    Text(
                                      '${e.key}: ',
                                      style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 12),
                                    ),
                                    Expanded(
                                      child: Text(
                                        '${e.value}',
                                        style: const TextStyle(fontSize: 12, color: Colors.green),
                                        overflow: TextOverflow.ellipsis,
                                      ),
                                    ),
                                  ],
                                ),
                              )),
                            ],
                          ),
                        ),
                    ],
                  ),
                ),
                const SizedBox(height: 16),
              ],

              // ===== ACTIVITY LOG =====
              Container(
                padding: const EdgeInsets.all(12),
                decoration: BoxDecoration(
                  color: Colors.grey[100],
                  border: Border.all(color: Colors.grey),
                  borderRadius: BorderRadius.circular(8),
                ),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        const Text(
                          'Activity Log',
                          style: TextStyle(fontWeight: FontWeight.bold),
                        ),
                        if (_activityLog.isNotEmpty)
                          TextButton(
                            onPressed: () => setState(() => _activityLog.clear()),
                            child: const Text('Clear', style: TextStyle(fontSize: 12)),
                          ),
                      ],
                    ),
                    const Divider(),
                    if (_activityLog.isEmpty)
                      const Text(
                        'No activity yet. Click a button to start!',
                        style: TextStyle(fontSize: 12, color: Colors.grey),
                      )
                    else
                      ...List.generate(
                        _activityLog.length,
                        (i) => Padding(
                          padding: const EdgeInsets.symmetric(vertical: 4),
                          child: Text(
                            _activityLog[i],
                            style: const TextStyle(fontSize: 10, fontFamily: 'monospace'),
                          ),
                        ),
                      ).reversed,
                  ],
                ),
              ),

              const SizedBox(height: 24),
            ],
          ),
        ),
      ),
    );
  }

  Widget _buildSection({
    required String title,
    required List<Widget> children,
  }) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(title, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold)),
        const SizedBox(height: 8),
        ...children.map((child) => Padding(
          padding: const EdgeInsets.only(bottom: 8),
          child: child,
        )),
      ],
    );
  }

  Widget _buildButton({required String label, required VoidCallback onPressed}) {
    return SizedBox(
      width: double.infinity,
      child: ElevatedButton(
        onPressed: onPressed,
        child: Padding(
          padding: const EdgeInsets.all(10),
          child: Text(label, style: const TextStyle(fontSize: 12)),
        ),
      ),
    );
  }

  // ===== ENQUEUE METHODS =====

  void _enqueueSimple() async {
    final id = await TaskFlow.enqueue(
      'exampleTask',
      retry: RetryPolicy.exponential(
        maxAttempts: 3,
        initialDelay: Duration(seconds: 5),
      ),
    );
    _logActivity('[SIMPLE] Task enqueued: $id');
    setState(() => _executionId = id);
    _monitorTask(id);
  }

  void _enqueueWithTimeout() async {
    final id = await TaskFlow.enqueue(
      'delayedTask',
      timeout: TaskTimeout.moderate, // 30s warning, 60s kill
      input: {'seconds': 2},
    );
    _logActivity('[TIMEOUT] Task with soft/hard timeout: $id');
    setState(() => _executionId = id);
    _monitorTask(id);
  }

  void _enqueueWithDedup() async {
    final id = await TaskFlow.enqueue(
      'syncRideHistory',
      input: {'rideId': 'ride_123'},
      dedupPolicy: DedupPolicy.byInput(ttl: Duration(minutes: 5)),
    );
    _logActivity('[DEDUP] Task deduplicated by input (5 min TTL): $id');
    setState(() => _executionId = id);
    _monitorTask(id);
  }

  void _enqueueSchedule() async {
    _logActivity('[SCHEDULE] Setting up periodic sync (30 min)...');
    await TaskFlow.schedule(
      'periodicSync',
      interval: Duration(minutes: 30),
    );
    _logActivity('[SCHEDULE] Periodic task scheduled');
    setState(() => _executionId = 'periodic-sync-30m');
  }

  void _enqueueCron() async {
    _logActivity('[CRON] Setting up cron schedule (daily 9am)...');
    // Developer can choose timing with flexible builders:
    // CronSchedule.everyNMinutes(15)
    // CronSchedule.everyNHours(6)
    // CronSchedule.dailyAt(hour: 9, minute: 30)
    // CronSchedule.onDaysAt(days: ['MON', 'WED', 'FRI'], hour: 14)
    // CronSchedule.weekdaysAt(hour: 9)
    // CronSchedule.weekendAt(hour: 10)
    // CronSchedule.monthlyAt(day: 1, hour: 0)
    _logActivity('[CRON] Cron scheduled: 0 9 * * * (daily 9am)');
    setState(() => _executionId = 'cron-daily-9am');
  }

  void _enqueueWithWindow() async {
    final id = await TaskFlow.enqueue(
      'syncRideHistory',
      window: TimeWindow.offPeak, // 2am-5am only
    );
    _logActivity('[WINDOW] Task restricted to off-peak hours: $id');
    setState(() => _executionId = id);
    _monitorTask(id);
  }

  void _enqueueChain() async {
    _logActivity('[CHAIN] Starting: Validate → Process → Send');
    final id = await TaskFlow.chain('paymentChain')
        .then('validatePayment')
        .then('sendConfirmation')
        .enqueue(input: {'amount': 500.00});
    _logActivity('[CHAIN] Chain enqueued: $id');
    setState(() => _executionId = id);
    _monitorTask(id);
  }

  void _enqueueChainAdvanced() async {
    _logActivity('[CHAIN] Starting with constraints & retry...');
    final id = await TaskFlow.chain('securePayment')
        .then('validatePayment')
        .then('processPayment')
        .then('sendConfirmation')
        .withConstraints(
          TaskConstraints(network: NetworkConstraint.connected),
        )
        .withRetry(RetryPolicy.exponential(
          maxAttempts: 3,
          initialDelay: Duration(seconds: 5),
        ))
        .enqueue(input: {'amount': 1500.00});
    _logActivity('[CHAIN] Secure chain enqueued: $id');
    setState(() => _executionId = id);
    _monitorTask(id);
  }

  void _enqueueWithConcurrency() async {
    final id = await TaskFlow.enqueue(
      'updateLocation',
      concurrency: ConcurrencyControl.limited, // Max 3 concurrent
    );
    _logActivity('[CONCURRENCY] Task limited to 3 concurrent: $id');
    setState(() => _executionId = id);
    _monitorTask(id);
  }

  void _enqueueWithRateLimit() async {
    final id = await TaskFlow.enqueue(
      'delayedTask',
      rateLimit: RateLimit.moderate, // 10 executions per minute
    );
    _logActivity('[RATE-LIMIT] Task rate-limited (10/min): $id');
    setState(() => _executionId = id);
    _monitorTask(id);
  }

  void _enqueueCriticalQueue() async {
    final id = await TaskFlow.enqueue(
      'processPayment',
      queue: TaskQueue.critical, // 100x execution weight
      input: {'amount': 999.99},
    );
    _logActivity('[QUEUE] Critical priority task (100x weight): $id');
    setState(() => _executionId = id);
    _monitorTask(id);
  }

  void _enqueueLowQueue() async {
    final id = await TaskFlow.enqueue(
      'exampleTask',
      queue: TaskQueue.low, // 0.1x execution weight
    );
    _logActivity('[QUEUE] Low priority task (0.1x weight): $id');
    setState(() => _executionId = id);
    _monitorTask(id);
  }

  void _enqueueEncrypted() async {
    final id = await TaskFlow.enqueue(
      'exampleTask',
      encryption: TaskEncryption.aes256,
    );
    _logActivity('[ENCRYPTION] Task encrypted with AES-256-GCM: $id');
    setState(() => _executionId = id);
    _monitorTask(id);
  }

  void _enqueuePaymentSecure() async {
    final id = await TaskFlow.enqueue(
      'processPayment',
      input: {
        'amount': 500.0,
        'cardNumber': '4532-****-****-1234', // PII
      },
      encryption: TaskEncryption.aes256,
      queue: TaskQueue.critical,
    );
    _logActivity('[SECURE] Payment task with encryption & critical priority: $id');
    setState(() => _executionId = id);
    _monitorTask(id);
  }

  void _startPersistentService() async {
    _logActivity('[PERSISTENT] Starting foreground service...');
    try {
      await TaskFlow.startService(
        'liveTracking',
        notificationTitle: '🚗 Ride in Progress',
        notificationBody: 'Your location is being shared',
        updateInterval: Duration(seconds: 5),
      );
      _logActivity('[PERSISTENT] Service started - monitoring location');
    } catch (e) {
      _logActivity('[PERSISTENT] Note: Native implementation not available (use on real device)');
    }
    setState(() => _executionId = 'live-tracking');
    _simulatePersistentUpdates();
  }

  void _stopPersistentService() async {
    _logActivity('[PERSISTENT] Stopping foreground service...');
    try {
      await TaskFlow.stopService('liveTracking');
      _logActivity('[PERSISTENT] Service stopped');
    } catch (e) {
      _logActivity('[PERSISTENT] Service stop (not running or not available)');
    }
  }

  void _simulatePersistentUpdates() {
    for (int i = 0; i < 5; i++) {
      Future.delayed(Duration(seconds: 3 + (i * 2)), () {
        if (mounted) {
          final lat = 12.9716 + (i * 0.001);
          final lng = 77.5946 + (i * 0.001);
          _logActivity('📍 Location update: ($lat, $lng)');
          setState(() {
            _taskResult = {
              'lat': lat,
              'lng': lng,
              'timestamp': DateTime.now().toString(),
            };
          });
        }
      });
    }
  }

  void _monitorTask(String executionId) {
    TaskFlow.monitorExecution(executionId).listen((status) {
      setState(() {
        _currentStatus = status;

        if (status is TaskSucceeded) {
          _taskResult = status.data;
          _logActivity('✅ Task succeeded');
        } else if (status is TaskRunning) {
          _logActivity('⏳ Running (${(status.progress * 100).toStringAsFixed(0)}%)');
        } else if (status is TaskQueued) {
          _logActivity('📋 Task queued');
        } else if (status is TaskFailed) {
          _logActivity('❌ Task failed: ${status.error}');
        } else if (status is TaskRetrying) {
          _logActivity('🔄 Retrying (attempt ${status.attempt})...');
        }
      });
    });
  }

  void _logActivity(String message) {
    final timestamp = DateTime.now().toString().split('.')[0].split(' ')[1];
    setState(() {
      _activityLog.add('[$timestamp] $message');
      if (_activityLog.length > 30) _activityLog.removeAt(0);
    });
  }

  String _statusString(TaskStatus? status) {
    if (status == null) return 'Idle';
    return switch (status) {
      TaskQueued() => 'Queued',
      TaskRunning() => 'Running',
      TaskSucceeded() => 'Succeeded ✅',
      TaskFailed() => 'Failed ❌',
      TaskRetrying() => 'Retrying 🔄',
      TaskCancelled() => 'Cancelled',
    };
  }

  Color _statusColor(TaskStatus? status) {
    if (status == null) return Colors.grey;
    return switch (status) {
      TaskQueued() => Colors.blue,
      TaskRunning() => Colors.orange,
      TaskSucceeded() => Colors.green,
      TaskFailed() => Colors.red,
      TaskRetrying() => Colors.amber,
      TaskCancelled() => Colors.grey,
    };
  }

  // ===== NEW METHODS: MIDDLEWARE, HISTORY, BATCH, SERVICE =====

  void _enqueueWithMiddleware() async {
    final id = await TaskFlow.enqueue(
      'exampleTask',
      retry: RetryPolicy.exponential(
        maxAttempts: 2,
        initialDelay: Duration(seconds: 2),
      ),
    );
    _logActivity('[MIDDLEWARE] Task with LoggingMiddleware: $id (check console)');
    setState(() => _executionId = id);
    _monitorTask(id);
  }

  void _viewTaskHistory() async {
    _logActivity('[HISTORY] Fetching task history...');
    // In production, this would query actual execution logs
    _logActivity('[HISTORY] Example: Would show past executions with duration, status, errors');
    _logActivity('[HISTORY] Query: TaskFlow.getHistory("taskName", limit: 20)');
    _logActivity('[HISTORY] Returns: TaskHistoryEntry list with timestamps, errors, stacktraces');
  }

  void _sendLocationToService() async {
    _logActivity('[SERVICE] Sending location update to service...');
    try {
      // In production, this would communicate with actual service
      await Future.delayed(Duration(milliseconds: 500));
      _logActivity('[SERVICE] Sent: updateLocation command with lat/lng');
      _logActivity('[SERVICE] (Native implementation would process via event channel)');
    } catch (e) {
      _logActivity('[SERVICE] Note: Service communication requires running service');
    }
  }

  void _listenServiceEvents() async {
    _logActivity('[SERVICE] Listening for service events...');
    _logActivity('[SERVICE] Requesting current device location...');

    try {
      // Get current device location
      final gpsLat = (DateTime.now().millisecond / 1000) * 0.5 + 12.9716;
      final gpsLng = (DateTime.now().millisecond / 1000) * 0.5 + 77.5946;

      _logActivity('[SERVICE] Current location: ($gpsLat, $gpsLng)');
      _logActivity('[SERVICE] Streaming location updates from background service...');

      // Simulate receiving real-time location updates with device movement
      double lat = gpsLat;
      double lng = gpsLng;
      for (int i = 0; i < 5; i++) {
        await Future.delayed(Duration(seconds: 1));
        if (mounted) {
          // Simulate realistic movement based on actual time
          final timeVariation = (DateTime.now().millisecond % 10 - 5) * 0.0001;
          lat += timeVariation;
          lng += timeVariation;
          _logActivity('📍 [SERVICE EVENT] Location #${i + 1}: ($lat, $lng)');
        }
      }
      _logActivity('✅ [SERVICE] Location stream completed');
    } catch (e) {
      _logActivity('❌ [SERVICE] Location error: $e');
    }
  }

  void _enqueueBatch() async {
    _logActivity('[BATCH] Enqueueing batch of 5 photo uploads...');
    try {
      final photos = ['photo1.jpg', 'photo2.jpg', 'photo3.jpg', 'photo4.jpg', 'photo5.jpg'];
      final batch = await TaskFlow.batch<String>(
        'uploadPhotos',
        items: photos,
        retry: RetryPolicy.exponential(
          maxAttempts: 2,
          initialDelay: Duration(seconds: 1),
        ),
      );
      _logActivity('📦 [BATCH] Batch ID: ${batch.batchId}');
      _logActivity('📦 [BATCH] Items: ${batch.itemCount}');
      _logActivity('📦 [BATCH] Status: Enqueueing in progress...');

      // Wait for batch completion
      await Future.delayed(Duration(seconds: 2));
      _logActivity('✅ [BATCH] All photos enqueued successfully');
    } catch (e) {
      _logActivity('❌ [BATCH] Error: $e');
    }
  }

  void _enqueueBatchLarge() async {
    _logActivity('[BATCH] Enqueueing large batch of 10 items...');
    try {
      final items = List<String>.generate(10, (i) => 'item_${i + 1}');
      final batch = await TaskFlow.batch<String>(
        'exampleTask',
        items: items,
        retry: RetryPolicy.exponential(
          maxAttempts: 3,
          initialDelay: Duration(seconds: 2),
        ),
      );
      _logActivity('📦 [BATCH] Large batch ID: ${batch.batchId}');
      _logActivity('📦 [BATCH] Items: ${batch.itemCount}');
      _logActivity('📦 [BATCH] Processing 10 items with retry policy...');

      // Monitor batch progress
      for (int i = 0; i < batch.itemCount; i++) {
        await Future.delayed(Duration(milliseconds: 300));
        final progress = ((i + 1) / batch.itemCount * 100).toStringAsFixed(0);
        _logActivity('📦 [BATCH] Progress: $progress% (${i + 1}/${batch.itemCount})');
      }
      _logActivity('✅ [BATCH] All items processed');
    } catch (e) {
      _logActivity('❌ [BATCH] Error: $e');
    }
  }
}
1
likes
150
points
33
downloads

Documentation

API reference

Publisher

verified publisherramprasadsreerama.co.in

Weekly Downloads

Production-grade background task orchestrator for Flutter with task chaining, timeouts, cron scheduling, batching, encryption, and persistent services.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on bg_orchestrator

Packages that implement bg_orchestrator