[pull] main from getsentry:main - #408
Merged
Merged
Conversation
…313) (#5813) * fix(replay): Skip buffer-mode replay capture when rate-limited (DART-313) In buffer (on-error) mode the recorder keeps running while rate-limited so the rolling buffer stays warm, but capturing on an error still encoded the current and buffered segments and handed them to the transport, which then dropped them. That wasted CPU, I/O, and MediaMuxer file descriptors on envelopes that could never be sent. Bail out of BufferCaptureStrategy.captureReplay when the Replay (or All) category is rate-limited, mirroring the guard session mode already applies. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * changelog * fix(replay): Record a lost replay event when buffer capture is rate-limited (DART-313) Skipping the encode when rate-limited meant the segments never reached the transport, so RateLimiter.filter never recorded them as lost. Replay drops in buffer mode silently vanished from client reports. Record a RATELIMIT_BACKOFF lost event for the Replay category at the bail-out, and move the rate-limit check below the sampling and isTerminating guards so we only report replays that would genuinely have been sent — a replay dropped by onErrorSampleRate is not a rate-limit loss, and a terminating one is deferred to the next launch rather than lost. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * changelog * fix(replay): Keep buffer mode while rate-limited (DART-313) Bailing out of BufferCaptureStrategy.captureReplay while rate-limited left isTerminating unset, so ReplayIntegration's unconditional convert() still swapped in a SessionCaptureStrategy. That discarded the rolling buffer, and the next recorded frame then hit checkCanRecord(), which pauses session mode when rate-limited and encodes a segment on the way out - exactly the work the bail-out was meant to avoid. It also left recording paused for the rest of the rate-limit window, contradicting onRateLimitChanged, which deliberately keeps buffer mode running. Stay in buffer mode while rate-limited so the buffer keeps rolling and the next error after the limit expires can send a complete replay. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
SessionCaptureStrategy and BufferCaptureStrategy differ only in when a recorded segment is sent, but nothing at the top of either class said so. Add a short KDoc to each pointing at the other, covering how the mode is selected, when segments are sent, and why ReplayIntegration pauses session mode while buffer mode keeps recording. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…updates (#5850) Bumps the github-actions group with 3 updates in the / directory: [getsentry/craft/.github/workflows/changelog-preview.yml](https://github.com/getsentry/craft), [saucelabs/saucectl-run-action](https://github.com/saucelabs/saucectl-run-action) and [getsentry/craft](https://github.com/getsentry/craft). Updates `getsentry/craft/.github/workflows/changelog-preview.yml` from 2.26.14 to 2.27.0 - [Release notes](https://github.com/getsentry/craft/releases) - [Changelog](https://github.com/getsentry/craft/blob/master/CHANGELOG.md) - [Commits](getsentry/craft@cdb657d...667b5f5) Updates `saucelabs/saucectl-run-action` from 4.4.0 to 4.5.0 - [Release notes](https://github.com/saucelabs/saucectl-run-action/releases) - [Commits](saucelabs/saucectl-run-action@bc81720...283660a) Updates `getsentry/craft` from 2.26.14 to 2.27.0 - [Release notes](https://github.com/getsentry/craft/releases) - [Changelog](https://github.com/getsentry/craft/blob/master/CHANGELOG.md) - [Commits](getsentry/craft@cdb657d...667b5f5) --- updated-dependencies: - dependency-name: getsentry/craft/.github/workflows/changelog-preview.yml dependency-version: 2.27.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions - dependency-name: saucelabs/saucectl-run-action dependency-version: 4.5.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions - dependency-name: getsentry/craft dependency-version: 2.27.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…#5814) * perf: Schedule rate-limit notifications on shared executor (JAVA-653) RateLimiter created a java.util.Timer whose thread stayed alive forever once the SDK got rate limited. Schedule the "rate limit lifted" observer notification on the shared timer executor instead, whose single worker thread is reused across all timeouts and self-terminates when idle. Pending notifications are cancelled on close(). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * changelog --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…t (JAVA-613) (#5792) * perf(core): Create outbox and cache dirs lazily instead of during init (JAVA-613) Sentry.initConfigurations created the outbox and cache directories synchronously on the init thread, which on Android is the main thread. Create each directory lazily in its consumer instead: the cache dir on the first envelope write (transport thread), and the outbox dir in the file-observer integration (executor thread) and before writing the startup-crash marker. The native SDK already creates the outbox dir itself during sentry_init, so NDK crash writes are unaffected. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * changelog Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ref(core): Encapsulate lazy dir creation in a LazyDirectory value object (JAVA-613) Replace the duplicated "create the dir if it does not exist" idiom in the envelope cache, outbox file observer, and startup-crash-marker paths with a single LazyDirectory type that materializes the directory on first access. CacheStrategy now owns its directory as a LazyDirectory: write paths call getOrCreate(), while path-building and validity checks use getFile() so they do not create the directory as a side effect. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ref(core): Inject the cache LazyDirectory via the constructor (JAVA-613) Have the composition roots (EnvelopeCache.create and AndroidEnvelopeCache) build the LazyDirectory and pass it into CacheStrategy, so the cache no longer constructs its own directory collaborator from a path string. The public String constructor is kept and delegates, preserving binary compatibility. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(core): Create the outbox dir in external envelope writers (JAVA-613) Creating the outbox dir lazily moved the mkdirs() off the init thread onto the SDK executor, so the dir is no longer guaranteed to exist once Sentry.init returns. Writers that drop envelopes into the outbox themselves raced that executor task and could fail with ENOENT, which is what EnvelopeTests.sendsNativeTransaction hit on a slow emulator. Have both external writers create the dir before writing, and document on getOutboxPath that the directory is created lazily so hybrid SDKs writing envelopes directly know they have to do the same. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(core): Create the cache dir before writing app-start config (JAVA-613) The removed init-time mkdirs() ran on the dsn-hashed cache path and created the un-hashed parent as a side effect. handleAppStartProfilingConfig writes app_start_profiling_config into that parent via createNewFile(), which fails with IOException when the parent is missing, and the surrounding catch swallows it into a log line. The next launch then finds no config and cannot start app-start profiling. This was masked because the profiling traces dir still calls mkdirs() on <cacheDir>/<dsnHash>/profiling_traces, creating the un-hashed grandparent -- but only when profiling is enabled, which every existing test did. The new test leaves profiling off so nothing else materializes the dir. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * ref(core): Simplify the lazy directory creation helpers (JAVA-613) The LazyDirectory value object was doing two unrelated jobs: holding a directory that a long-lived cache creates on first write, and acting as a one-shot mkdirs() helper at three call sites that constructed it only to discard it immediately. Split those apart. FileUtils.createDirectory covers the one-shot case and returns whether the directory exists afterwards, so the callers log the failure instead of discarding mkdirs()' return value and failing later in an unrelated-looking write. LazyDirectory keeps only the cache use and gains resolve(), which creates the parent before returning the child, so write paths no longer depend on an earlier getOrCreate() call having run. Creation is deliberately not cached: on Android the cache dir lives under Context.getCacheDir(), which the system may wipe at any time, so each write re-checks and the directory heals itself. Also revert the LazyDirectory injection into CacheStrategy. Nothing injected a custom instance, so it only added a public EnvelopeCache constructor to the API surface for an internal change. * fix(core): Report success when losing the createDirectory race (JAVA-613) File.mkdirs() returns false both when it cannot create the directory and when another thread got there first, so createDirectory reported a failure for a directory that was present. Callers act on that by skipping their write: a startup crash would go unmarked and the app-start profiling config would not be written, even though the directory existed. Re-check for the directory when mkdirs() fails, which separates losing the race from a genuine failure such as missing permissions. The added test fails reliably without the fix, with most of the racing threads observing false. * fix(core): Don't recreate the cache dir when discarding (JAVA-613) getCurrentFile went through LazyDirectory.resolve, which creates the directory as a side effect. discard() calls it while deleting from the cache, so discarding an envelope could resurrect a cache dir that had just been removed. Compute the path without touching the filesystem instead, and drop resolve entirely: the remaining write paths already call getOrCreate once before writing. * docs(core): Note the lazy dir creation as a behavioral change (JAVA-613) Sentry.init used to mkdirs() the outbox and cache dirs synchronously, so both were guaranteed to exist once it returned. They are now created by whichever component first writes into them, off the init thread, which breaks anyone writing envelopes into the outbox path directly instead of going through the SDK -- notably the hybrid SDKs' captureEnvelope. Call that out under Behavioral Changes so hybrid maintainers see it; the existing Performance entry only describes the win, not the cost. * docs(core): Explain why LazyDirectory swallows a failed mkdirs (JAVA-613) getOrCreate() ignoring the return value of createDirectory() reads like an oversight next to the callers that do log it, so record that write paths already surface the failure via their own error handling. --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
#5836) Commit updates the platform used with ANR profiles from Java to Android so that we can properly bill ANR profiling under UI Profile Hours rather than Continuous Profile Hours. Depends on the updates made in [Relay #6183](getsentry/relay#6183), [getsentry #118849](getsentry/sentry#118849), [vroomrs #93](getsentry/vroomrs#93), and [vroom #672](getsentry/vroom#672). Co-authored-by: Markus Hintersteiner <markus.hintersteiner@sentry.io>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
See Commits and Changes for more details.
Created by
pull[bot] (v2.0.0-alpha.4)
Can you help keep this open source service alive? 💖 Please sponsor : )