S3: Stability and performance fixes - #741
Merged
Merged
Conversation
🦋 Changeset detectedLatest commit: b4288e8 The changes in this PR will be included in the next version bump. This PR includes changesets to release 13 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
rkistner
marked this pull request as ready for review
August 3, 2026 12:48
stevensJourney
approved these changes
Aug 4, 2026
stevensJourney
left a comment
Collaborator
There was a problem hiding this comment.
The changes make sense, look reasonable and are implemented cleanly.
Codex pointed out that we're missing a Changeset entry to @powersync/service-core - but I think we already have other Changeset entries on main for that package, so it should not cause any publishing issues I believe.
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 join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Bugfix
An error during the initial snapshot can cause an uncaught rejection that kills the process. This is because the
initialSnapshotDonepromise is unusued in that case. The fix just silences the uncaught rejection by doing.catch(() => {}). This affected MongoDB replication using MongoDB V3 storage.Performance Improvements
These were performance issues that I picked up during an initial round of performance testing. Without these fixes, the performance using S3 was significantly slower than V1 storage, both for replication and syncing. With these fixes, the performance is on par or faster in my tests.
Concurrent Uploads
The compact process already does concurrent uploads to S3, but the replication process still processed uploads sequentially. This refactors to also do concurrent uploads when replicating.
Inline threshold size
This increases the threshold from 1KB -> 16KB. During performance testing, I found that having 1000x 1KB S3 objects in one batch just adds too much overhead. 16KB should work better.
The trade-off here is increased source db load and potential memory usage. For example, when we query for 1000 chunks/documents for a sync request, this can be up to 16MB of data now.
Redo sync batching (getBucketDataBatch)
In V1 storage, sync batching roughly works as follows:
In V3 storage, we don't limit by operation count on the db level. So instead we had:
Step 5 above effectively matched the old behavior from the client's point-of-view. The issue is that it caused a lot of rework:
This rewrites the batching process to effectively remove step 4 and 5. Instead, we send all data that we have loaded already, to prevent that rework.
This is still limited to 16MB, so the upper limit on the amount of data we keep in memory is still lower than the 64MB in V1 storage.
We could reduce memory usage for some cases further by:
There were some tests that relied on the assumption of an exact limit of 1000 per batch. This rewrites some of those tests to not rely on that assumption anymore.
This also returns exactly one bucket definition group per batch now. Once one group is complete, we effectively start from scratch with a new database query, so there is no gain in continuing the current batch. This does change the return type: we may now yield a global
{ hasMore: true }flag, indicating the client should fetch another batch, even if every individual chunk had{ has_more: false }.AI Usage
Manually guided the optimizations, using Codex gpt-5.6 to implement them and rewrite the tests. Manually simplified and optimized
getBucketDataBatch.