feat(mikrotik): optimize address list entry addition with chunked execution and improved error handling
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m46s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m46s
This commit is contained in:
@@ -1477,6 +1477,7 @@ async function getAddressLists(req, res) {
|
||||
const ADDRESS_LIST_PATH = 'ip/firewall/address-list';
|
||||
const ADDRESS_LIST_REMOVE_CHUNK_SIZE = 100;
|
||||
const ADDRESS_LIST_ADD_CONCURRENCY = 8;
|
||||
const ADDRESS_LIST_ADD_EXECUTE_CHUNK_SIZE = 80;
|
||||
|
||||
function chunkArray(items, size) {
|
||||
if (!Array.isArray(items) || items.length === 0) return [];
|
||||
@@ -1529,8 +1530,8 @@ async function removeAddressListIds(client, ids) {
|
||||
return removed;
|
||||
}
|
||||
|
||||
async function addAddressListEntries(client, entries) {
|
||||
const normalized = [...new Map(
|
||||
function normalizeAddressListEntries(entries) {
|
||||
return [...new Map(
|
||||
(Array.isArray(entries) ? entries : [])
|
||||
.map((entry) => {
|
||||
const address = String(entry?.address || '').trim();
|
||||
@@ -1544,14 +1545,36 @@ async function addAddressListEntries(client, entries) {
|
||||
})
|
||||
.filter(Boolean)
|
||||
).values()];
|
||||
}
|
||||
|
||||
if (normalized.length === 0) return { added: 0, failed: 0 };
|
||||
function escapeRouterOsString(value) {
|
||||
return `"${String(value || '')
|
||||
.replace(/\\/g, '\\\\')
|
||||
.replace(/"/g, '\\"')}"`;
|
||||
}
|
||||
|
||||
function buildAddressListAddScript(entriesChunk) {
|
||||
return entriesChunk
|
||||
.map((params) => {
|
||||
const parts = [
|
||||
'/ip/firewall/address-list/add',
|
||||
`address=${escapeRouterOsString(params.address)}`,
|
||||
`list=${escapeRouterOsString(params.list)}`,
|
||||
];
|
||||
if (params.comment != null && String(params.comment).trim()) {
|
||||
parts.push(`comment=${escapeRouterOsString(params.comment)}`);
|
||||
}
|
||||
return parts.join(' ');
|
||||
})
|
||||
.join(';\n');
|
||||
}
|
||||
|
||||
async function addAddressListEntriesParallel(client, normalized) {
|
||||
if (!Array.isArray(normalized) || normalized.length === 0) return { added: 0, failed: 0 };
|
||||
let index = 0;
|
||||
let added = 0;
|
||||
let failed = 0;
|
||||
const workersCount = Math.min(ADDRESS_LIST_ADD_CONCURRENCY, normalized.length);
|
||||
|
||||
const workers = Array.from({ length: workersCount }, async () => {
|
||||
while (true) {
|
||||
const current = index;
|
||||
@@ -1567,11 +1590,40 @@ async function addAddressListEntries(client, entries) {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await Promise.all(workers);
|
||||
return { added, failed };
|
||||
}
|
||||
|
||||
async function addAddressListEntries(client, entries) {
|
||||
const normalized = normalizeAddressListEntries(entries);
|
||||
if (normalized.length === 0) return { added: 0, failed: 0 };
|
||||
|
||||
let added = 0;
|
||||
let failed = 0;
|
||||
const chunks = chunkArray(normalized, ADDRESS_LIST_ADD_EXECUTE_CHUNK_SIZE);
|
||||
|
||||
for (const chunk of chunks) {
|
||||
const script = buildAddressListAddScript(chunk);
|
||||
try {
|
||||
// Один execute на пачку резко снижает HTTP overhead.
|
||||
await client.command('execute', { script });
|
||||
added += chunk.length;
|
||||
continue;
|
||||
} catch (err) {
|
||||
console.warn(
|
||||
`[address-lists] execute add fallback (${chunk.length} entries):`,
|
||||
err?.message || String(err)
|
||||
);
|
||||
}
|
||||
|
||||
const fallbackResult = await addAddressListEntriesParallel(client, chunk);
|
||||
added += fallbackResult.added;
|
||||
failed += fallbackResult.failed;
|
||||
}
|
||||
|
||||
return { added, failed };
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/mikrotik/address-lists/apply-summary
|
||||
* Body: { serverId, removeIds: string[], addEntries: { address, list, comment? }[] }
|
||||
|
||||
Reference in New Issue
Block a user