Skip to content

feat: offline caching (inproc & breakpad)#1490

Open
jpnurmi wants to merge 34 commits intomasterfrom
jpnurmi/feat/offline-caching
Open

feat: offline caching (inproc & breakpad)#1490
jpnurmi wants to merge 34 commits intomasterfrom
jpnurmi/feat/offline-caching

Conversation

@jpnurmi
Copy link
Collaborator

@jpnurmi jpnurmi commented Jan 23, 2026

Summary

Adds offline caching support for the inproc and breakpad backends, allowing envelopes to be persisted locally for debugging and offline scenarios. When enabled, envelopes are retained in a cache/ subdirectory within the database path, regardless of whether the send succeeds or fails.

On startup, the cache is pruned based on the configured limits (max items, age, size), removing entries from oldest to newest until constraints are satisfied. The pruning algorithm is based on Crashpad's prune_crash_reports.cc.

API

New options:

  • sentry_options_set_cache_keep(opts, int enabled) - Enables/disables offline caching
  • sentry_options_set_cache_max_items(opts, size_t items) - Maximum number of cache entries (default: 30)
  • sentry_options_set_cache_max_size(opts, size_t bytes) - Maximum cache directory size (no default max size)
  • sentry_options_set_cache_max_age(opts, time_t seconds) - Maximum age for cache entries (no default max age)

Usage

sentry_options_set_cache_keep(options, true);
sentry_options_set_cache_max_items(options, 10);              // 10 items
sentry_options_set_cache_max_size(options, 8 * 1024 * 1024);  // 8 MB
sentry_options_set_cache_max_age(options, 30 * 24 * 60 * 60); // 30 days

Comparison

Option Native Cocoa/iOS Java/Android
Enable/disable cache_keep (default: off) Always on Always on
Max items cache_max_items (30) maxCacheItems (30) maxCacheItems (30)
Max size cache_max_size (0) - -
Max age cache_max_age (0) - (90 days, hardcoded) -

Limitations

Related

Test Plan

  • Unit tests for age-based and size-based cache pruning logic (test_cache.c)
  • Integration tests for end-to-end caching behavior (test_integration_cache.py)

Co-authored-by: @JoshuaMoelans
Closes: #1461

JoshuaMoelans and others added 16 commits January 23, 2026 14:21
Before "revert separate caching folder implementation"

#1461
Cast cache_max_age to time_t to avoid implicit signedness conversion
between uint64_t and time_t.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add explicit static_cast<time_t>() for cache_max_age to fix
-Wsign-conversion warning on Windows with clang-cl.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@jpnurmi jpnurmi changed the title WIP: offline caching + tests for inproc & breakpad feat: offline caching (inproc & breakpad) Jan 26, 2026
@github-actions
Copy link

github-actions bot commented Jan 26, 2026

Messages
📖 Do not forget to update Sentry-docs with your feature once the pull request gets approved.

Generated by 🚫 dangerJS against 8a17813

jpnurmi and others added 3 commits January 27, 2026 13:57
For consistency with time-related operations throughout the codebase.

This adds a time.h dependency to the public header, but it's a
lightweight standard C header available since C89.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@jpnurmi jpnurmi marked this pull request as ready for review February 3, 2026 11:02
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
jpnurmi and others added 2 commits February 3, 2026 12:53
Subtract file size from accumulated_size when a file is pruned (by age
or size). Previously, pruned files' sizes were still counted, causing
subsequent valid files to be incorrectly pruned when both cache_max_age
and cache_max_size were set.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
jpnurmi and others added 2 commits February 3, 2026 13:13
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move size accumulation into else branch so age-pruned files don't count
toward size limit. Remove the size subtraction on prune which caused
bin-packing behavior (keeping older smaller files while removing newer
larger ones).

Add test for size-based pruning order.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
jpnurmi and others added 2 commits February 4, 2026 10:29
- Check CreateFileW return value before calling SetFileTime/CloseHandle
- Change TEST_CHECK to TEST_ASSERT since mtime setup is a precondition

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
cache_dir is NULL when cache_keep is false, and sentry__path_free
handles NULL safely.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

jpnurmi and others added 2 commits February 4, 2026 11:31
Crashpad's AgePruneCondition and DatabaseSizePruneCondition only accept
days and KB respectively, causing precision loss for sub-day ages and
sub-KB sizes. Replace them with MaxAgePruneCondition (seconds) and
MaxSizePruneCondition (bytes) that handle zero as "no limit" internally.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
jpnurmi and others added 5 commits February 4, 2026 16:50
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Re-order cache_max_items before max_size/max_age for visibility as the
most relevant default limit.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants