Changelog
View SourceAll notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[Unreleased]
[0.3.0] - 2026-01-06
Changed
- BREAKING: Offset format redesigned - Now uses
erlang:unique_integer([:monotonic, :positive])formatted as 16-char hex instead of timestamp-sequence-random format- Offsets are now clock-independent and guaranteed monotonic
- Old offsets from previous versions are incompatible
- BREAKING: Version requirements updated - Now requires Elixir 1.19+ and Erlang/OTP 27+ (uses stdlib
:jsonmodule) - ETS storage optimized - Data table key changed from
{stream_id, sequence}to{stream_id, offset_integer}enabling O(log n) seeking viaets:next/2instead of O(n) full table scan - ETS iteration refactored - Unified iteration with
reduce_stream/3andreduce_stream_from/4primitives (reduce_while pattern) - O(1) offset lookups - Stream struct now tracks
current_offsetandearliest_offsetfields, eliminating ETS iteration for these lookups - ETS concurrency improved - Added
write_concurrency: trueto all ETS tables for better multi-stream throughput - Code deduplication -
read/2andread_messages/2now share implementation viaread_internal/3 - Timestamps for retention are now stored separately in ETS, not extracted from offsets
- Removed
@seq_tableETS table (no longer needed)
Fixed
list_streams_with_retention/0now uses ETS match specification for efficient filtering instead of loading all streams into memory
Removed
Offset.timestamp/1function - offsets no longer contain timestampsOffset.generate/1with sequence parameter - offsets are now generated without sequence input
Added
Offset.to_integer/1function - converts offset string to integer for ETS key operations
[0.2.0] - 2025-01-05
Added
- Retention policies for automatic stream compaction
max_age: Remove messages older than specified duration (milliseconds)max_messages: Keep at most N messages in streammax_bytes: Keep at most N bytes of data in stream
410 GoneHTTP response for compacted offsets withStream-Earliest-OffsetheaderDurableStreams.Retention.Supervisor- OTP supervisor for retention subsystemDurableStreams.Retention.Scheduler- Periodic GenServer for compaction schedulingDurableStreams.Retention.Worker- Stateless module for stream compactionOffset.timestamp/1function to extract timestamp from offsets- Storage functions for retention queries:
get_first_message_timestamp/1find_offset_after_timestamp/2find_offset_after_n_messages/2find_offset_after_n_bytes/2delete_messages_before/2update_after_compaction/4list_streams_with_retention/0
Changed
- Stream struct now tracks
message_count,total_bytes, andearliest_offset - Storage
append/3now updates message count and byte tracking - Application supervision tree now includes Retention.Supervisor
Removed
DurableStreams.Protocol.V1Plug- useDurableStreams.Protocol.Plugwith a forwarding router instead
[0.1.0] - 2025-01-05
Added
- Full HTTP protocol implementation (PUT, POST, GET, DELETE, HEAD)
- JSON mode with array flattening for
application/jsonstreams - Long-polling support with
live=truequery parameter - Server-Sent Events (SSE) support with
live=ssequery parameter - Stream TTL and expiration via
Stream-TTLandStream-Expires-Atheaders - Sequence ordering enforcement via
Stream-Seqheader - ETag-based caching with
If-None-Matchsupport - OTP supervision tree with per-stream GenServer processes
- ETS-based storage backend
- Phoenix.PubSub integration for live update notifications
DurableStreams.StreamManagerprogrammatic APIDurableStreams.Protocol.Plugfor Phoenix integrationDurableStreams.Protocol.V1Plugfor standalone HTTP serverDurableStreams.LiveViewhelper module for Phoenix LiveView integrationmix durable_streams.conformancetask for running conformance tests- 100% conformance with official Durable Streams protocol tests (131/131)
Notes
- Package name is
streamkeeper, module namespace isDurableStreams - Phoenix LiveView is an optional dependency (module only compiles when available)