-
-
Notifications
You must be signed in to change notification settings - Fork 85
Open
Labels
component/integrationWeb framework integrationWeb framework integrationcomponent/mqMessage queue relatedMessage queue relatedexamplesExample code relatedExample code relatedgood first issueGood for newcomersGood for newcomerstype/enhancementImprovements to existing featuresImprovements to existing features
Description
Summary
Add a SQLite-based MessageQueue implementation to the @fedify/sqlite package to complement the existing SqliteKvStore. This would enable complete Fedify stack deployment without requiring Redis or PostgreSQL infrastructure, particularly beneficial for single-node instances.
Motivation
Currently, @fedify/sqlite provides SqliteKvStore but no MessageQueue implementation, unlike @fedify/redis and @fedify/postgres which offer both. This creates an asymmetry where users choosing SQLite for key–value storage must still set up additional infrastructure for message queuing.
Use cases that would benefit:
- Personal or small community fediverse instances running on single servers
- Development and testing environments
- Self-hosted instances prioritizing simplicity and minimal infrastructure
- Docker/container deployments aiming for single-container operation
Proposed implementation
Core features
- ACID-compliant message enqueue/dequeue operations
- Topic-based message routing
- Retry mechanism with configurable attempts
- Message expiration/cleanup policies
- WAL mode for improved concurrency
Example schema
CREATE TABLE IF NOT EXISTS fedify_message_queue (
id INTEGER PRIMARY KEY AUTOINCREMENT,
payload TEXT NOT NULL,
created INTEGER NOT NULL,
scheduled INTEGER NOT NULL,
processed INTEGER,
retry_count INTEGER DEFAULT 0,
max_retries INTEGER DEFAULT 3,
error TEXT
);
CREATE INDEX IF NOT EXISTS idx_scheduled_processed
ON fedify_message_queue(scheduled, processed);API design
The implementation should follow the existing MessageQueue interface:
export class SqliteMessageQueue implements MessageQueue {
readonly nativeRetrial = false;
constructor(db: Database, options?: SqliteMessageQueueOptions);
enqueue(
message: any,
options?: MessageQueueEnqueueOptions,
): Promise<void>;
enqueueMany?(
messages: any[],
options?: MessageQueueEnqueueOptions,
): Promise<void>;
listen(
handler: (message: any) => Promise<void> | void,
options?: MessageQueueListenOptions,
): Promise<void>;
}Limitations and considerations
Explicit limitations
This implementation would be explicitly designed for single-node deployments only:
- Cannot be used in multi-node/distributed setups
- Write operations are serialized even in WAL mode
- Not suitable for very high throughput scenarios (thousands of messages per second)
- Network file systems (NFS) are not recommended
Documentation requirements
- Clear documentation stating “single-node only” constraint
- Performance characteristics and expected throughput
- Migration path from SQLite to Redis/PostgreSQL as applications scale
- Best practices for
PRAGMAsettings and performance tuning
Technical considerations
Concurrency handling
- Use WAL mode for better read concurrency
- Implement proper locking with
SELECT ... FOR UPDATEor equivalent - Prevent duplicate message processing in multi-worker scenarios
Performance optimization
- Configurable
PRAGMAsettings (journal_mode,synchronous,cache_size, etc.) - Efficient indexing for topic-based queries
- Batch processing capabilities
- Periodic cleanup of processed messages
Error handling
- Dead letter queue for repeatedly failed messages
- Configurable retry delays (exponential backoff)
- Logging of processing errors
Benefits
- Simplified deployment: Complete Fedify stack with just SQLite
- Consistent backup: Single SQLite file for both
KvStoreandMessageQueue - Lower operational overhead: No additional services to manage
- Better DX: Easier local development setup
Open questions
- Should
SqliteKvStoreandSqliteMessageQueueshare the same SQLite database file, or use separate files? - What default values should we use for retry counts, cleanup intervals, etc.?
- Should timestamp columns use
INTEGER(Unix timestamp in milliseconds) orTEXT(ISO 8601 format)?
Related work
- sqlite-queue
- better-sqlite3-queue
- Celery's SQLite broker support
Metadata
Metadata
Assignees
Labels
component/integrationWeb framework integrationWeb framework integrationcomponent/mqMessage queue relatedMessage queue relatedexamplesExample code relatedExample code relatedgood first issueGood for newcomersGood for newcomerstype/enhancementImprovements to existing featuresImprovements to existing features