Skip to content

Classify browser upload outcomes

tutorial
TL;DR

This browser helper sends one bounded Arrow IPC upload and classifies the response without clearing input or silently retrying. Supply encoded bytes and their expected row count. Preserve input after partial or unknown outcomes; even a fully admitted batch has not necessarily reached your application’s required durability boundary.

Message sequenceAn HTTP response reports admitted rows, not downstream completion
An HTTP response reports admitted rows, not downstream completionA producer encodes Arrow IPC and posts it to the token-scoped ingestion endpoint. BoilStream validates and admits rows, then returns a response. The current handler admits a validated request as one group; unexpected counts and missing responses require reconciliation.ProducerBoilStreamEncode Arrow IPC streamPOST /ingest/{token}Validate schema and admit rowsStatus and admitted row countCompare sent and reported rowsTime moves downward · dashed arrows are responsesAn HTTP response reports admitted rows, not downstream completionA producer encodes Arrow IPC and posts it to the token-scoped ingestion endpoint. BoilStream validates and admits rows, then returns a response. The current handler admits a validated request as one group; unexpected counts and missing responses require reconciliation.ProducerBoilStreamEncode Arrow IPC streamPOST /ingest/{token}Validate schema and admitrowsStatus and admitted rowcountCompare sent and reportedrowsTime moves downward · dashed arrows are responses
Successful admission should report the full request count. Reconcile unexpected counts or lost responses before replaying.

Encode data with an Arrow library using the target schema, then pass the resulting Uint8Array and its row count to this function. It sends one request, retains the caller’s bytes, and reports the outcome. It does not clear a queue or silently retry.

JavaScript
async function uploadArrow(endpoint, bytes, expectedRows, maxBytes = 128 * 1024) {
if (!Number.isSafeInteger(maxBytes) || maxBytes <= 0 ||
!(bytes instanceof Uint8Array) || bytes.byteLength === 0 ||
bytes.byteLength > maxBytes || !Number.isSafeInteger(expectedRows) ||
expectedRows <= 0) {
throw new Error('Provide a nonempty, bounded Arrow batch and its row count');
}
let response;
let body;
try {
response = await fetch(endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/vnd.apache.arrow.stream' },
body: bytes
});
body = await response.json();
} catch {
return { outcome: 'unknown' };
}
if (response.status === 200 && body?.status === 'success' &&
Number.isSafeInteger(body.rows) && body.rows >= 0 && body.rows <= expectedRows) {
return {
outcome: body.rows === expectedRows ? 'admitted' : 'partial',
admittedRows: body.rows
};
}
if (response.status === 429 || response.status === 503) {
const delay = body?.retry_after_ms;
return {
outcome: 'retry-later',
status: response.status,
retryAfterMs: Number.isSafeInteger(delay) && delay > 0 ? delay : null
};
}
if ([400, 401, 403, 404, 405].includes(response.status)) {
return { outcome: 'rejected', status: response.status };
}
return { outcome: 'unknown', status: response.status };
}

The 128 KiB value is a client-side example bound, not a promise about server request-size limits. Use bounded batches and one upload at a time. Keep a bounded pending queue or a durable application outbox if data must survive a browser close.

Only remove input from the pending queue after the outcome required by your application. admitted establishes memory admission only. For retry-later, preserve the same bytes; retry a confirmed pre-admission rejection after the indicated delay, with a retry limit. For partial or unknown, retain the input and reconcile it instead of retrying blindly. Application event IDs help reconciliation but do not automatically enable server deduplication.

The current server admits a validated request as one group. The helper retains its partial outcome defensively for an unexpected count mismatch. retry-later is a signal to inspect the refusal, not permission to replay: confirm the server’s pre-admission contract first. A 503 status alone can also mean an uncertain outcome.