Skip to content

Commit 07dcc98

Browse files
committed
Increase CLI upload batch size
1 parent cf369a9 commit 07dcc98

2 files changed

Lines changed: 38 additions & 27 deletions

File tree

src/lib/api-client.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -404,8 +404,8 @@ class SecureApiClient {
404404
// Validate and sanitize sessions
405405
const sanitizedSessions = sessions.map(session => this.sanitizeSession(session));
406406

407-
// Keep upload batches small so a single request cannot overwhelm server-side processing.
408-
const MAX_UPLOAD_BATCH_SIZE = 10;
407+
// Keep request count low while gzip and server-side async queueing keep large uploads manageable.
408+
const MAX_UPLOAD_BATCH_SIZE = 100;
409409
const chunks = [];
410410

411411
for (let i = 0; i < sanitizedSessions.length; i += MAX_UPLOAD_BATCH_SIZE) {

tests/unit/lib/api-client.test.ts

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ import { setupTestEnv, cleanupTestEnv, testData } from '../../test-utils';
99
vi.mock('axios');
1010
vi.mock('../../../src/lib/config');
1111

12+
function decodeUploadBody(body: any): any {
13+
if (Buffer.isBuffer(body)) {
14+
return JSON.parse(gunzipSync(body).toString('utf-8'));
15+
}
16+
return body;
17+
}
18+
1219
describe('API Client Module', () => {
1320
let mockAxiosInstance: any;
1421
let apiClient: any;
@@ -447,65 +454,69 @@ describe('API Client Module', () => {
447454

448455
describe('Batch Upload', () => {
449456
it('should handle large session batches', async () => {
450-
// Create 25 sessions (should be split into 3 batches of 10, 10, and 5)
451-
const sessions = Array.from({ length: 25 }, () => testData.createSession());
457+
// Create 250 sessions (should be split into 3 batches of 100, 100, and 50)
458+
const sessions = Array.from({ length: 250 }, () => testData.createSession());
452459

453460
mockAxiosInstance.post.mockResolvedValue({
454-
data: { success: true, created: 10, duplicates: 0 },
461+
data: { success: true, created: 100, duplicates: 0 },
455462
});
456463

457464
await apiClient.uploadSessions(sessions);
458465

459466
// Should make 3 calls for batches
460467
expect(mockAxiosInstance.post).toHaveBeenCalledTimes(3);
461468

462-
// First batch should have 10 sessions
463-
expect(mockAxiosInstance.post.mock.calls[0][1].sessions).toHaveLength(10);
464-
expect(mockAxiosInstance.post.mock.calls[0][1].batchNumber).toBe(1);
465-
expect(mockAxiosInstance.post.mock.calls[0][1].totalBatches).toBe(3);
469+
const firstPayload = decodeUploadBody(mockAxiosInstance.post.mock.calls[0][1]);
470+
const secondPayload = decodeUploadBody(mockAxiosInstance.post.mock.calls[1][1]);
471+
const thirdPayload = decodeUploadBody(mockAxiosInstance.post.mock.calls[2][1]);
472+
473+
// First batch should have 100 sessions
474+
expect(firstPayload.sessions).toHaveLength(100);
475+
expect(firstPayload.batchNumber).toBe(1);
476+
expect(firstPayload.totalBatches).toBe(3);
466477

467-
// Second batch should have 10 sessions
468-
expect(mockAxiosInstance.post.mock.calls[1][1].sessions).toHaveLength(10);
469-
expect(mockAxiosInstance.post.mock.calls[1][1].batchNumber).toBe(2);
470-
expect(mockAxiosInstance.post.mock.calls[1][1].totalBatches).toBe(3);
478+
// Second batch should have 100 sessions
479+
expect(secondPayload.sessions).toHaveLength(100);
480+
expect(secondPayload.batchNumber).toBe(2);
481+
expect(secondPayload.totalBatches).toBe(3);
471482

472-
// Third batch should have the remaining 5 sessions
473-
expect(mockAxiosInstance.post.mock.calls[2][1].sessions).toHaveLength(5);
474-
expect(mockAxiosInstance.post.mock.calls[2][1].batchNumber).toBe(3);
475-
expect(mockAxiosInstance.post.mock.calls[2][1].totalBatches).toBe(3);
483+
// Third batch should have the remaining 50 sessions
484+
expect(thirdPayload.sessions).toHaveLength(50);
485+
expect(thirdPayload.batchNumber).toBe(3);
486+
expect(thirdPayload.totalBatches).toBe(3);
476487

477488
for (const call of mockAxiosInstance.post.mock.calls) {
478-
expect(call[1].sessions.length).toBeLessThanOrEqual(10);
489+
expect(decodeUploadBody(call[1]).sessions.length).toBeLessThanOrEqual(100);
479490
}
480491
});
481492

482493
it('should aggregate results from multiple batches', async () => {
483-
const sessions = Array.from({ length: 25 }, () => testData.createSession());
494+
const sessions = Array.from({ length: 250 }, () => testData.createSession());
484495

485496
mockAxiosInstance.post
486497
.mockResolvedValueOnce({
487-
data: { success: true, created: 8, duplicates: 2 },
498+
data: { success: true, created: 80, duplicates: 20 },
488499
})
489500
.mockResolvedValueOnce({
490-
data: { success: true, created: 7, duplicates: 3 },
501+
data: { success: true, created: 75, duplicates: 25 },
491502
})
492503
.mockResolvedValueOnce({
493-
data: { success: true, created: 4, duplicates: 1 },
504+
data: { success: true, created: 40, duplicates: 10 },
494505
});
495506

496507
const result = await apiClient.uploadSessions(sessions);
497508

498-
expect(result.created).toBe(19); // 8 + 7 + 4
499-
expect(result.duplicates).toBe(6); // 2 + 3 + 1
500-
expect(result.sessionsProcessed).toBe(25); // Total
509+
expect(result.created).toBe(195); // 80 + 75 + 40
510+
expect(result.duplicates).toBe(55); // 20 + 25 + 10
511+
expect(result.sessionsProcessed).toBe(250); // Total
501512
});
502513

503514
it('should call progress callback during batch upload', async () => {
504-
const sessions = Array.from({ length: 25 }, () => testData.createSession());
515+
const sessions = Array.from({ length: 250 }, () => testData.createSession());
505516
const progressCallback = vi.fn();
506517

507518
mockAxiosInstance.post.mockResolvedValue({
508-
data: { success: true, created: 10, duplicates: 0 },
519+
data: { success: true, created: 100, duplicates: 0 },
509520
});
510521

511522
await apiClient.uploadSessions(sessions, progressCallback);

0 commit comments

Comments
 (0)