Skip to content

feat(synapse-sdk): batch storage uploads by default - #935

Open
hugomrdias wants to merge 2 commits into
hugomrdias/batchingfrom
hugomrdias/batching-sdk
Open

feat(synapse-sdk): batch storage uploads by default#935
hugomrdias wants to merge 2 commits into
hugomrdias/batchingfrom
hugomrdias/batching-sdk

Conversation

@hugomrdias

@hugomrdias hugomrdias commented Aug 24, 2026

Copy link
Copy Markdown
Member

Summary

  • add a core piece batcher that groups addPieces work while respecting transaction message-size limits
  • enable batching by default for StorageManager.upload() and StorageContext.upload()
  • preserve the SDK's default two-copy flow: upload to a primary provider, pull to secondary providers, then batch each provider's on-chain commit independently
  • expose delay and limiter wait strategies through Synapse, plus synapse.storage.flush() for explicitly releasing limiter-held batches
  • allow callers to opt out with pieceBatching: false

Usage

Batching is enabled by default, using a zero-delay window:

const synapse = await Synapse.create({
  privateKey,
  rpcUrl,
})

The delay can be configured when creating the client:

const synapse = await Synapse.create({
  privateKey,
  rpcUrl,
  pieceBatching: {
    wait: { kind: 'delay', ms: 100 },
  },
})

The limiter strategy holds a batch until it reaches the transaction size boundary or the application flushes it:

const synapse = await Synapse.create({
  privateKey,
  rpcUrl,
  pieceBatching: {
    wait: { kind: 'limiter' },
  },
})

const uploads = files.map((file) => synapse.storage.upload(file))
await synapse.storage.flush()
const results = await Promise.all(uploads)

To retain the previous immediate, per-upload behavior:

const synapse = await Synapse.create({
  privateKey,
  rpcUrl,
  pieceBatching: false,
})

How it works

  1. StorageManager.upload() resolves the primary and secondary contexts exactly as before, including the default request for at least two copies.
  2. The primary upload is parked at its provider. Once parked, each secondary starts its provider-to-provider pull from the primary.
  3. A Synapse-scoped coordinator assigns the upload or pull to a batcher keyed by provider and data set. Providers therefore submit separate batches, while compatible pieces for the same data set share one transaction.
  4. The core batcher waits according to the configured delay or limiter and automatically splits batches that would exceed the encoded addPieces message-size limit.
  5. All pieces in a submitted batch share the confirmation request. Each upload resolves to its own piece ID using its batch index.
  6. Newly created data-set IDs are synchronized back into their storage contexts so later uploads reuse the established data set.

The existing result and failure semantics remain intact: successful copies are returned in copies, intermediate provider failures remain in failedAttempts, and the manager still throws StoreError or CommitError when the corresponding operation cannot succeed.

The split store(), pull(), and commit() APIs remain unchanged and unbatched. flush() waits for uploads and pulls to finish parking before releasing all current windows; the core batcher's close() prevents new work and delegates to that same flush behavior.

Compatibility

  • batching can be disabled with pieceBatching: false
  • the public PdpDataSet contract remains unchanged
  • the core custom limiter contract still receives the data set and pending pieces
  • session-key signing uses the delegated client while preserving the root payer

Tests

  • packages/synapse-core build
  • packages/synapse-sdk build
  • package lint
  • core Node tests: 858 passing
  • core browser tests: 858 passing
  • SDK Node tests: 280 passing, 7 pending
  • SDK browser tests: 280 passing, 7 pending

@hugomrdias
hugomrdias requested a review from rvagg as a code owner August 24, 2026 16:41
@github-project-automation github-project-automation Bot moved this to 📌 Triage in FOC Aug 24, 2026
@hugomrdias
hugomrdias changed the base branch from master to hugomrdias/batching August 24, 2026 16:51
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 24, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
synapse-dev c71be31 Commit Preview URL

Branch Preview URL
Aug 26 2026, 12:14 PM

@FilOzzy FilOzzy moved this from 📌 Triage to 🔎 Awaiting review in FOC Aug 25, 2026
Comment thread packages/synapse-sdk/src/storage/piece-batching.ts Outdated
Comment thread packages/synapse-sdk/src/storage/manager.ts Outdated
Comment thread packages/synapse-sdk/src/storage/manager.ts Outdated
@hugomrdias
hugomrdias requested review from a team, BigLep, jennijuju and rjan90 as code owners August 26, 2026 12:01
@hugomrdias
hugomrdias requested review from BravoNatalie and removed request for a team, BigLep, jennijuju and rjan90 August 26, 2026 12:13

@BravoNatalie BravoNatalie left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Things look good to me! The only thing my agent found was some testing hardening, which I left as a comment.

)
})

it('should reject concurrent uploads cleanly when shared batch entry creation fails', async () => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Before the fix, both promises were already rejecting with expected. The issue was the extra unhandled rejection from void existing.then(...).

Could we also check that no unhandledrejection happens? Maybe with a Node subprocess using --unhandled-rejections=strict? Since Chromium only logs page errors without failing the test, I think reverting the fix could still leave this test green.

@hugomrdias hugomrdias linked an issue Aug 27, 2026 that may be closed by this pull request
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: 🔎 Awaiting review

Development

Successfully merging this pull request may close these issues.

Stateful batching

3 participants