Notification Queue Management
Relevant source files
The following files were used as context for generating this wiki page:
- app/src/main/kotlin/com/fathiraz/flowbell/domain/usecases/HandleNotificationQueueUseCase.kt
- app/src/main/kotlin/com/fathiraz/flowbell/data/repositories/NotificationQueueRepositoryImpl.kt
- app/src/main/kotlin/com/fathiraz/flowbell/data/local/database/dao/NotificationQueueDao.kt
- app/src/main/kotlin/com/fathiraz/flowbell/data/services/NotificationListenerService.kt
- app/src/main/kotlin/com/fathiraz/flowbell/data/local/database/FlowBellDatabase.kt
- app/src/main/kotlin/com/fathiraz/flowbell/data/local/database/entities/NotificationQueue.kt (Inferred from FlowBellDatabase.kt)
- app/src/main/kotlin/com/fathiraz/flowbell/data/mappers/NotificationMapper.kt
Notification Queue Management in FlowBell is the system responsible for capturing, storing, and orchestrating the delivery of Android notifications to external webhooks. It serves as a reliable buffer that ensures notifications are not lost during network instability and provides a historical record of all delivery attempts, including successes, failures, and HTTP metadata.
The system utilizes a local Room database (FlowBellDatabase) to persist notification logs and manages their lifecycle through a combination of a background service (NotificationListenerService), repository patterns, and batch processing logic. This architecture allows the app to handle notification bursts effectively by grouping outgoing requests and managing retries for failed deliveries.
Sources: README.md:95-103, NotificationListenerService.kt:70-85, NotificationQueueRepositoryImpl.kt:15-20
Architecture and Data Flow
The architecture follows Clean Architecture principles, separating the concerns into presentation, domain, and data layers. The queue management logic is primarily driven by the NotificationListenerService, which acts as the entry point for system notifications.
The diagram shows the lifecycle of a notification from system capture to webhook delivery and database persistence.
Sources: NotificationListenerService.kt:130-170, NotificationQueueDao.kt:14-25
Components and Responsibilities
| Component | Responsibility |
|---|---|
NotificationListenerService | Listens for system notifications, filters them based on user preferences, and manages the in-memory batch processing. |
NotificationQueueDao | Provides low-level SQLite access for inserting, updating, and querying notification logs. |
NotificationQueueRepositoryImpl | Bridges the domain and data layers, handling mapping between database entities and domain models. |
HandleNotificationQueueUseCase | Encapsulates high-level business logic for saving, fetching, and cleaning up notifications. |
NotificationMapper | Utility for converting data between different formats (Domain, Entity, and Webhook Payload). |
Sources: NotificationListenerService.kt:45-60, NotificationQueueRepositoryImpl.kt:15-25, HandleNotificationQueueUseCase.kt:11-15
Queue States and Lifecycle
Notifications within the queue transition through several states represented by the NotificationQueueStatus enum.
State Transitions
- PENDING: The initial state when a notification is captured and added to the database before delivery.
- PROCESSING: (Internal status) Used when notifications are being actively handled by the batch processor.
- SENT: Set when the webhook responds with a 2xx status code.
- FAILED: Set when the webhook delivery fails (e.g., non-2xx response or network exception).
This diagram illustrates the status transitions managed by the NotificationQueueRepository.
Sources: NotificationQueueRepositoryImpl.kt:193-207, NotificationQueueDao.kt:60-95
Database Schema and Persistence
The notification_queue table in the Room database stores all metadata and delivery details.
| Field | Type | Description |
|---|---|---|
id | Long (PK) | Auto-generated unique identifier. |
packageName | String | Package name of the source app. |
status | String | Current queue status (PENDING, SENT, etc.). |
retryCount | Integer | Number of delivery attempts made. |
httpResponseCode | Integer | The status code returned by the webhook. |
errorMessage | String | Details of any exception or HTTP error body. |
createdAt | Long | Unix timestamp of when the entry was created. |
Sources: FlowBellDatabase.kt:34-52, NotificationQueueDao.kt:150-165
Batch Processing Logic
To optimize battery and network usage, the system processes notifications in batches rather than individual requests.
- Trigger Interval: The
NotificationListenerServiceruns a batch processing job every 5 seconds. - Batching Mechanism: Captured notifications are added to a
ConcurrentLinkedQueuein memory before being persisted and sent. - HTTP Details: Upon delivery, the system records the request method, URL, duration, and response body for debugging purposes.
// From NotificationListenerService.kt:98-116
private fun startBatchProcessing() {
batchProcessingJob?.cancel()
batchProcessingJob = serviceScope.launch {
while (true) {
try {
delay(5000)
if (notificationBatch.isNotEmpty()) {
processBatch()
}
} catch (e: Exception) {
Timber.e(e, "Error in batch processing loop")
}
}
}
}
Sources: NotificationListenerService.kt:98-116, NotificationListenerService.kt:225-250
Maintenance and Cleanup
The system includes automated and manual maintenance functions to prevent database bloat.
- Automatic Cleanup:
NotificationQueueDaoprovides methods to delete oldSENTnotifications based on a cutoff time. - Batch Deletion: The repository supports clearing old notifications older than a specific number of days.
- Cleanup Implementation:
// From HandleNotificationQueueUseCase.kt:53-70 suspend fun cleanupOldNotifications(olderThanDays: Int): Result<Int> { return try { val result = notificationRepository.deleteOldNotifications(olderThanDays) result } catch (e: Exception) { Result.failure(e) } }
Sources: NotificationQueueDao.kt:125-145, NotificationQueueRepositoryImpl.kt:177-185, HandleNotificationQueueUseCase.kt:53-70
Conclusion
Notification Queue Management is the backbone of FlowBell's reliability. By combining local persistence with batch delivery and detailed status tracking, the system provides a robust bridge between Android system events and user-defined automation webhooks. The architecture ensures that even during network downtime, notifications are queued locally and can be reviewed or retried later via the Notification History interface.