Skip to content

Commit 9a25664

Browse files
authored
refactor: move batch execute to oss (#9754)
1 parent e6d55ab commit 9a25664

File tree

2 files changed

+93
-0
lines changed

2 files changed

+93
-0
lines changed

src/lib/util/batchExecute.test.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { jest } from '@jest/globals';
2+
import { batchExecute } from './batchExecute';
3+
4+
jest.useFakeTimers();
5+
6+
describe('batchExecute', () => {
7+
let mockExecuteFn: jest.Mock;
8+
9+
beforeEach(() => {
10+
mockExecuteFn = jest.fn();
11+
});
12+
13+
afterEach(() => {
14+
jest.clearAllTimers();
15+
jest.clearAllMocks();
16+
});
17+
18+
it('should process each item in batches of the specified size', async () => {
19+
const items = Array.from({ length: 25 }, (_, i) => i);
20+
const batchSize = 10;
21+
const delayMs = 1000;
22+
23+
batchExecute(items, batchSize, delayMs, mockExecuteFn);
24+
25+
for (let i = 0; i < 2; i++) {
26+
jest.advanceTimersByTime(delayMs);
27+
await Promise.resolve();
28+
}
29+
30+
expect(mockExecuteFn).toHaveBeenCalledTimes(items.length);
31+
items.forEach((item, index) => {
32+
expect(mockExecuteFn).toHaveBeenNthCalledWith(index + 1, item);
33+
});
34+
});
35+
36+
it('should delay between each batch', async () => {
37+
const items = Array.from({ length: 15 }, (_, i) => i);
38+
const batchSize = 5;
39+
const delayMs = 1000;
40+
41+
batchExecute(items, batchSize, delayMs, mockExecuteFn);
42+
43+
expect(mockExecuteFn).toHaveBeenCalledTimes(5);
44+
45+
jest.advanceTimersByTime(delayMs);
46+
await Promise.resolve();
47+
expect(mockExecuteFn).toHaveBeenCalledTimes(10);
48+
49+
jest.advanceTimersByTime(delayMs);
50+
await Promise.resolve();
51+
expect(mockExecuteFn).toHaveBeenCalledTimes(15);
52+
});
53+
54+
it('should handle empty items array without calling executeFn', async () => {
55+
const items: number[] = [];
56+
const batchSize = 10;
57+
const delayMs = 1000;
58+
59+
await batchExecute(items, batchSize, delayMs, mockExecuteFn);
60+
61+
expect(mockExecuteFn).not.toHaveBeenCalled();
62+
});
63+
64+
it('should handle a batch size larger than the number of items', async () => {
65+
const items = [1, 2, 3];
66+
const batchSize = 10;
67+
const delayMs = 1000;
68+
69+
batchExecute(items, batchSize, delayMs, mockExecuteFn);
70+
71+
expect(mockExecuteFn).toHaveBeenCalledTimes(items.length);
72+
items.forEach((item, index) => {
73+
expect(mockExecuteFn).toHaveBeenNthCalledWith(index + 1, item);
74+
});
75+
});
76+
});

src/lib/util/batchExecute.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
export const batchExecute = async <T>(
2+
items: T[],
3+
batchSize: number,
4+
delayMs: number,
5+
executeFn: (item: T) => void,
6+
) => {
7+
for (let i = 0; i < items.length; i += batchSize) {
8+
const batch = items.slice(i, i + batchSize);
9+
10+
// Execute function for each item in the batch sequentially, fire-and-forget
11+
batch.forEach((item) => executeFn(item));
12+
13+
if (i + batchSize < items.length) {
14+
await new Promise((resolve) => setTimeout(resolve, delayMs));
15+
}
16+
}
17+
};

0 commit comments

Comments
 (0)