Skip to main content

Offline Message Queueing & Delivery πŸ“¬

Never lose a message again! Vaultys Peer SDK automatically handles offline peers with intelligent message queueing and guaranteed delivery.

🎯 The Challenge of P2P Messaging​

In traditional P2P applications, if a peer is offline, messages are lost. This creates a poor user experience:

  • ❌ Users miss important messages
  • ❌ Manual retry logic is complex
  • ❌ No delivery guarantees
  • ❌ Poor reliability perception

✨ Our Solution: Seamless Offline Handling​

Vaultys Peer SDK solves this with automatic message queueing:

  • βœ… 100% message delivery - Messages queue when peers are offline
  • βœ… Seamless reconnection - Queued messages deliver automatically
  • βœ… No code changes - Works with existing sendMessage() calls
  • βœ… Persistent storage - Queues survive app restarts
  • βœ… Smart retry logic - Exponential backoff prevents overload

πŸš€ Zero-Configuration Usage​

Message queueing works out of the box - no configuration needed!

import { setupVaultysPeerSDK } from '@vaultys/peer-sdk';

const peer = setupVaultysPeerSDK();
await peer.initialize('did:vaultys:alice');

// Just send messages normally - queueing is automatic!
await peer.sendMessage('did:vaultys:bob', 'Hello Bob!');
// If Bob is offline, message queues automatically
// When Bob comes online, message delivers seamlessly

πŸ“š How It Works​

Message Flow Diagram​

Queue Behavior​

  1. Detection: SDK automatically detects if peer is offline
  2. Queueing: Messages are queued in order (FIFO)
  3. Storage: Queue persists to configured storage provider
  4. Monitoring: SDK monitors for peer reconnection
  5. Delivery: When peer reconnects, messages deliver in order
  6. Confirmation: Delivery is confirmed before removing from queue

🎨 Configuration Options​

While queueing works by default, you can customize the behavior:

const peer = setupVaultysPeerSDK({
messageQueue: {
// Enable/disable queueing (default: true)
enabled: true,

// Maximum messages to queue per peer
maxQueueSize: 1000,

// Maximum time to keep messages (ms)
maxQueueTime: 7 * 24 * 60 * 60 * 1000, // 7 days

// Persist queue to storage (survives restarts)
persistQueue: true,

// Retry strategy
retryStrategy: 'exponential', // or 'linear', 'fixed'

// Initial retry delay (ms)
retryDelay: 1000,

// Maximum retry attempts
maxRetries: 10,

// Batch delivery size
batchSize: 50,

// Compress queued messages
compression: true
}
});

πŸ’‘ Common Patterns​

1. Send and Forget​

The simplest pattern - just send messages without worrying about online status:

// No need to check if peer is online!
async function sendChatMessage(did: string, text: string) {
await peer.sendMessage(did, text);
// SDK handles everything else
}

2. Track Delivery Status​

Monitor when messages are actually delivered:

// Send with tracking
const messageId = await peer.sendMessage(did, 'Important message');

// Track delivery
peer.on('message-delivered', (delivery) => {
if (delivery.messageId === messageId) {
console.log('βœ… Message delivered at:', delivery.timestamp);
updateUIDeliveryStatus(messageId, 'delivered');
}
});

// Track queueing
peer.on('message-queued', (event) => {
console.log('πŸ“¬ Message queued for offline peer:', event.to);
updateUIDeliveryStatus(event.messageId, 'pending');
});

3. Priority Messages​

Send high-priority messages that deliver first:

// High priority message
await peer.sendMessage(did, 'URGENT: Server maintenance', 'text', null, {
priority: 'high',
skipQueue: false // Still queue if offline
});

// Normal priority (default)
await peer.sendMessage(did, 'Regular update');

4. Bulk Messaging​

Send to multiple peers efficiently:

// Send to multiple peers - each queues independently
const recipients = ['did:vaultys:alice', 'did:vaultys:bob', 'did:vaultys:charlie'];

const results = await Promise.all(
recipients.map(did =>
peer.sendMessage(did, 'Team announcement')
.then(id => ({ did, messageId: id, status: 'sent' }))
.catch(err => ({ did, error: err, status: 'failed' }))
)
);

// Some may be delivered immediately, others queued
console.log('Delivery results:', results);

5. Queue Management​

Inspect and manage the message queue:

// Get queue status
const queueInfo = peer.getQueueInfo();
console.log(`Total queued messages: ${queueInfo.totalMessages}`);
console.log(`Peers with queued messages: ${queueInfo.peersWithMessages}`);

// Get queued messages for specific peer
const queuedMessages = peer.getQueuedMessages('did:vaultys:bob');
console.log(`${queuedMessages.length} messages queued for Bob`);

// Clear queue for specific peer (use with caution!)
await peer.clearQueue('did:vaultys:bob');

// Retry failed messages immediately
await peer.retryFailedMessages();

πŸ”„ Retry Strategies​

Exponential Backoff (Default)​

Delays double with each retry, preventing server overload:

// Retry delays: 1s, 2s, 4s, 8s, 16s, 32s...
const peer = setupVaultysPeerSDK({
messageQueue: {
retryStrategy: 'exponential',
retryDelay: 1000,
maxRetries: 10
}
});

Linear Backoff​

Delays increase linearly:

// Retry delays: 1s, 2s, 3s, 4s, 5s...
const peer = setupVaultysPeerSDK({
messageQueue: {
retryStrategy: 'linear',
retryDelay: 1000,
maxRetries: 10
}
});

Fixed Interval​

Same delay between retries:

// Retry every 5 seconds
const peer = setupVaultysPeerSDK({
messageQueue: {
retryStrategy: 'fixed',
retryDelay: 5000,
maxRetries: 10
}
});

🎯 Advanced Features​

Message Deduplication​

Prevents duplicate messages from being queued:

const peer = setupVaultysPeerSDK({
messageQueue: {
deduplication: true,
deduplicationWindow: 60000 // 1 minute window
}
});

// These will be deduplicated if sent within window
await peer.sendMessage(did, 'Hello');
await peer.sendMessage(did, 'Hello'); // Ignored if within window

Queue Persistence​

Queues survive app restarts:

const peer = setupVaultysPeerSDK({
storageProvider: new IndexedDBProvider(), // or any persistent provider
messageQueue: {
persistQueue: true,
persistenceKey: 'vaultys-message-queue'
}
});

// On app restart, queued messages are restored and delivery continues

Batch Delivery​

Deliver multiple queued messages efficiently:

const peer = setupVaultysPeerSDK({
messageQueue: {
batchSize: 50, // Deliver up to 50 messages at once
batchDelay: 100 // Wait 100ms between batches
}
});

Message Expiration​

Auto-remove old messages from queue:

const peer = setupVaultysPeerSDK({
messageQueue: {
maxQueueTime: 24 * 60 * 60 * 1000, // 24 hours
cleanupInterval: 60 * 60 * 1000 // Check every hour
}
});

peer.on('message-expired', (event) => {
console.log('Message expired:', event.messageId);
});

πŸš€ Coming Soon: Relay Server​

We're open-sourcing our production-grade signaling server that also acts as a message relay!

What's Coming​

// Deploy your own relay server
// docker run -p 9000:9000 vaultys/signaling-relay

const peer = setupVaultysPeerSDK({
relay: {
host: 'your-relay.com',
port: 9000
},

relay: {
enabled: true,
maxOfflineTime: '30d', // Store for 30 days
maxMessageSize: '100MB', // Support large files
encryptAtRest: true, // Server-side encryption
}
});

// Messages relay through server for extended offline periods
await peer.sendMessage(did, 'Delivered even after weeks offline!');

Relay Features​

  • πŸ“¦ Extended Storage: Keep messages for days or weeks
  • πŸ” End-to-end Encryption: Server can't read messages
  • πŸ“Š Analytics: Message delivery metrics
  • 🌍 Global Distribution: Deploy relays worldwide
  • ⚑ High Performance: Handle millions of messages
  • πŸ”„ Automatic Failover: Multiple relay support

πŸ“Š Monitoring & Metrics​

Track queue performance:

// Get queue metrics
const metrics = peer.getQueueMetrics();
console.log('Queue metrics:', {
totalQueued: metrics.totalQueued,
totalDelivered: metrics.totalDelivered,
totalFailed: metrics.totalFailed,
averageQueueTime: metrics.averageQueueTime,
deliveryRate: metrics.deliveryRate
});

// Monitor queue events
peer.on('queue-stats', (stats) => {
updateDashboard({
queueSize: stats.size,
oldestMessage: stats.oldestMessageAge,
deliveryRate: stats.deliveryRate
});
});

🎯 Best Practices​

Do's βœ…β€‹

  • Let the SDK handle queueing automatically
  • Monitor delivery events for UI updates
  • Set reasonable queue size limits
  • Use persistent storage for important messages
  • Implement message expiration for time-sensitive content

Don'ts βŒβ€‹

  • Don't implement manual retry logic
  • Don't check peer status before sending
  • Don't store unlimited messages
  • Don't disable queueing without good reason
  • Don't clear queues without user consent

πŸ”§ Troubleshooting​

Common Issues​

IssueSolution
Messages not queueingCheck messageQueue.enabled is true
Queue growing too largeReduce maxQueueSize or add expiration
Messages not deliveringCheck peer connection and retry settings
Duplicate messagesEnable deduplication
Lost messages on restartEnable persistQueue with persistent storage

Debug Mode​

const peer = setupVaultysPeerSDK({
debug: true,
messageQueue: {
debugQueue: true // Extra queue logging
}
});

// Monitor all queue operations
peer.on('queue-operation', (op) => {
console.log('Queue operation:', op);
});

πŸŽ‰ Conclusion​

With Vaultys Peer SDK's automatic message queueing, you can build reliable P2P applications that work seamlessly regardless of peer connectivity. Your users will never miss a message, and you'll never have to write complex retry logic again!


Next: Learn about Passkey Authentication for passwordless security