outbox_queue 0.1.0
outbox_queue: ^0.1.0 copied to clipboard
A durable outbox for offline-first apps — queue writes while the network is gone, replay them in order when it returns, with backoff, lanes and dead-lettering.
example/outbox_queue_example.dart
import 'dart:io';
import 'dart:math';
import 'package:outbox_queue/outbox_queue.dart';
/// A till that keeps taking sales while the network is down.
Future<void> main() async {
final outbox = Outbox(
store: FileOutboxStore(Directory('.outbox')),
maxAttempts: 6,
);
// Two independent streams of work. A sale that the server keeps rejecting
// must not hold up a stock correction queued behind it.
outbox.register('sale', (operation) async {
final ok = await _post('/sales', operation);
return ok ? OutboxVerdict.done : OutboxVerdict.retry;
});
outbox.register('stock-adjustment', (operation) async {
final ok = await _post('/stock', operation);
return ok ? OutboxVerdict.done : OutboxVerdict.retry;
});
outbox.stats.listen(
(s) => stdout.writeln('unsent: ${s.total} parked: ${s.deadLettered}'));
await outbox.enqueue(
type: 'sale',
lane: 'sales',
payload: {'items': 3, 'total': 47.80, 'method': 'cash'},
);
await outbox.enqueue(
type: 'stock-adjustment',
lane: 'stock',
payload: {'sku': 'NL-001', 'delta': -3},
);
// Call this when connectivity returns, on resume, or on a timer. The queue
// does not watch the network itself — the app knows more about when a retry
// is worth making.
await outbox.drain();
await outbox.dispose();
}
/// Stands in for a real client. Fails about half the time, as a bad connection
/// does.
Future<bool> _post(String path, OutboxOperation operation) async {
await Future<void>.delayed(const Duration(milliseconds: 50));
final ok = Random().nextBool();
stdout.writeln('POST $path ${operation.id} -> ${ok ? 'ok' : 'failed'}');
return ok;
}