Skip to content

Commit 3e78865

Browse files
SK-3133 add SDK Guidelines: Unary vs Bulk Operations to flowvault README
New top-level section (after VaultController -- Unary operations, before Bulk Insert) covering: - Unary vs Bulk: when to use each, mirroring the structural comparison table already in the README with practical decision guidance. - The N < batchSize trap where bulk resolves to concurrency=1 with none of the batching benefit. - Concurrency guidelines: a starting-point sizing formula (N_cpu x U_cpu x (1 + W/C)) for ..._CONCURRENCY_LIMIT, with guidance to benchmark and raise incrementally rather than jump to the formula's theoretical max. Also renames the existing structural comparison heading from "Unary vs. bulk" to "Unary vs. bulk Parity" to disambiguate it from the new guidance section's title. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
1 parent e70e792 commit 3e78865

1 file changed

Lines changed: 58 additions & 2 deletions

File tree

flowvault/README.md

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,12 @@ The `flowvault` module is a Skyflow Java SDK built for high-throughput vault ope
3434
- [Schema vs. schemaless vaults](#schema-vs-schemaless-vaults)
3535
- [Batching and concurrency](#batching-and-concurrency)
3636
- [VaultController — Unary operations](#vaultcontroller--unary-operations)
37-
- [Unary vs. bulk](#unary-vs-bulk)
37+
- [Unary vs. bulk Parity](#unary-vs-bulk-parity)
3838
- [Vault type support](#vault-type-support)
39+
- [SDK Guidelines: Unary vs Bulk Operations](#sdk-guidelines-unary-vs-bulk-operations)
40+
- [Unary](#unary)
41+
- [Bulk](#bulk)
42+
- [Concurrency guidelines](#concurrency-guidelines)
3943
- [Bulk Insert](#bulk-insert)
4044
- [Bulk Tokenize](#bulk-tokenize)
4145
- [Bulk Detokenize](#bulk-detokenize)
@@ -629,7 +633,7 @@ Alongside the bulk methods, `VaultController` exposes five **unary** operations.
629633

630634
Each method also accepts an optional options object (`InsertOptions`, `DetokenizeOptions`, `GetOptions`, `UpdateOptions`, `DeleteOptions`) — see [Custom Request Headers](#custom-request-headers).
631635

632-
## Unary vs. bulk
636+
## Unary vs. bulk Parity
633637

634638
Everything the bulk machinery adds — batching, concurrency, the payload ceiling, the summary, the per-item index — is absent here. What survives is the per-record reporting:
635639

@@ -655,6 +659,58 @@ The same distinction as [Schema vs. schemaless vaults](#schema-vs-schemaless-vau
655659
| `delete` | Structured vaults — deletes a table's records. Distinct from `bulkDeleteTokens`, which removes tokens only and leaves the record in place. |
656660
| `detokenize` | Both — detokenizing only needs the token itself, not a table, so it works regardless of which kind of vault the token came from. |
657661

662+
# SDK Guidelines: Unary vs Bulk Operations
663+
664+
Both **Unary** and **Bulk** operations accept as many records as you pass. The key difference is **how the SDK makes HTTP calls and manages concurrency**.
665+
666+
## Unary
667+
668+
- Makes **exactly one HTTP call per SDK invocation**, regardless of the number of records.
669+
- The application is responsible for any **chunking, batching, and concurrency**.
670+
- Best suited for:
671+
- Single-event or low-volume ingestion
672+
- Interactive or user-facing requests where immediate results are required
673+
- Applications that already have their own concurrency or job-management mechanism
674+
675+
**Use Unary when you want the application to control request execution.**
676+
677+
## Bulk
678+
679+
- The SDK automatically splits records into `batchSize`-sized chunks.
680+
- It dispatches up to `concurrencyLimit` batches in parallel.
681+
- The SDK therefore owns **batching, parallel dispatch, and request coordination**.
682+
- Best suited for:
683+
- Large datasets
684+
- Imports and backfills
685+
- ETL and data migration workloads
686+
- Bulk/streaming ingestion where you want the SDK to manage batching and concurrency
687+
688+
**Use Bulk when you want the SDK to optimize request execution for high-volume workloads.**
689+
690+
A bulk call sent with fewer records than `batchSize` (default 50) still produces exactly one batch — `concurrency` resolves to 1 regardless of `..._CONCURRENCY_LIMIT` — so there's no batching benefit, only the overhead of the bulk machinery on top. Use unary instead for calls at that size.
691+
692+
## Concurrency guidelines
693+
694+
For Bulk operations, choose `concurrencyLimit` based on the available CPU and the ratio of task wait time to compute time:
695+
696+
```
697+
concurrency ≈ N_cpu × U_cpu × (1 + W/C)
698+
```
699+
700+
Where:
701+
702+
- `N_cpu` = number of CPU cores available to the process
703+
- `U_cpu` = target CPU utilization, between 0 and 1
704+
- `W` = wait time / API latency per call
705+
- `C` = compute time per call — approximately **5 ms for the SDK**
706+
707+
### Practical guidance
708+
709+
- **VUs ≤ 20:** a single CPU core is generally sufficient.
710+
- **VUs > 20:** consider increasing CPU capacity and tune concurrency accordingly.
711+
- For higher-throughput workloads, **dual- or quad-core** configurations are a good starting point.
712+
- Start with the formula as a baseline and **benchmark with your actual API latency and workload** before increasing concurrency further.
713+
658714
# Bulk Insert
659715

660716
Insert many records — even across different tables — in a single call. Each record is a `BulkInsertRequestRecord` with its own `data` and, optionally, its own `tableName` and `upsert`.

0 commit comments

Comments
 (0)