батчинг
This commit is contained in:
@@ -5,6 +5,7 @@ import { IList } from '@pnp/sp/lists';
|
|||||||
import '@pnp/sp/items';
|
import '@pnp/sp/items';
|
||||||
import '@pnp/sp/site-users/web';
|
import '@pnp/sp/site-users/web';
|
||||||
import '@pnp/sp/profiles';
|
import '@pnp/sp/profiles';
|
||||||
|
import '@pnp/sp/batching';
|
||||||
import { getImpersonatedEmail } from '../impersonation';
|
import { getImpersonatedEmail } from '../impersonation';
|
||||||
import { IApprovalRow } from './models/IApprovalRow';
|
import { IApprovalRow } from './models/IApprovalRow';
|
||||||
import { IMatrixRow } from './models/IMatrixRow';
|
import { IMatrixRow } from './models/IMatrixRow';
|
||||||
@@ -106,11 +107,31 @@ export class ApprovalListService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const { a, order } of withOrder.filter((x) => !!x.a.email)) {
|
const toWrite = withOrder.filter((x) => !!x.a.email);
|
||||||
const approverId = await this.resolveUserId(a.email);
|
if (toWrite.length === 0) return;
|
||||||
await this.list().items.add({
|
|
||||||
|
// Резолв Id согласующих — независимые запросы (ensureUser по email),
|
||||||
|
// ждать их по очереди незачем. На длинном маршруте (десяток+ шагов) это
|
||||||
|
// было основным источником задержки наравне с самой записью строк ниже.
|
||||||
|
const approverIds = await Promise.all(toWrite.map(({ a }) => this.resolveUserId(a.email)));
|
||||||
|
|
||||||
|
// Сами строки — ОДНИМ HTTP-запросом через batch API SharePoint, а не по
|
||||||
|
// POST на строку: add() на batched-инстансе не уходит в сеть сразу, а
|
||||||
|
// копится и отправляется одним вызовом по execute().
|
||||||
|
//
|
||||||
|
// ВАЖНО: batchedList (сам список) переиспользуем, а .items достаём ЗАНОВО
|
||||||
|
// на каждой итерации — PnPjs один и тот же Items-инстанс во второй add()
|
||||||
|
// внутри одного батча не даёт («This instance is already part of a batch»,
|
||||||
|
// см. docs/concepts/batching#reuse). .getById(id) ниже в deleteForRequest
|
||||||
|
// этой проблемы не имеет — он и так создаёт новый инстанс на каждый вызов.
|
||||||
|
const [batchedSP, execute] = getSP().batched();
|
||||||
|
const batchedList = batchedSP.web.lists.getByTitle(this.listTitle);
|
||||||
|
toWrite.forEach(({ a, order }, i) => {
|
||||||
|
// void: промис от add() на batched-инстансе нарочно не ждём поштучно —
|
||||||
|
// он разрешится вместе со всеми остальными после execute() ниже.
|
||||||
|
void batchedList.items.add({
|
||||||
Title: a.position || a.email,
|
Title: a.position || a.email,
|
||||||
[`${FIELDS.approver}Id`]: approverId,
|
[`${FIELDS.approver}Id`]: approverIds[i],
|
||||||
[FIELDS.status]: status,
|
[FIELDS.status]: status,
|
||||||
[`${FIELDS.ticket}Id`]: requestId,
|
[`${FIELDS.ticket}Id`]: requestId,
|
||||||
[FIELDS.order]: order,
|
[FIELDS.order]: order,
|
||||||
@@ -120,7 +141,8 @@ export class ApprovalListService {
|
|||||||
[FIELDS.slaHours]: a.slaHours ?? null,
|
[FIELDS.slaHours]: a.slaHours ?? null,
|
||||||
[FIELDS.askOverdueReason]: a.askOverdueReason ?? null,
|
[FIELDS.askOverdueReason]: a.askOverdueReason ?? null,
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
|
await execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Продвигает очередь: среди ещё не активных строк со статусом «Ждёт очереди»
|
// Продвигает очередь: среди ещё не активных строк со статусом «Ждёт очереди»
|
||||||
@@ -344,9 +366,18 @@ export class ApprovalListService {
|
|||||||
// Удаляет все строки согласования по заявке (при возврате/повторной отправке).
|
// Удаляет все строки согласования по заявке (при возврате/повторной отправке).
|
||||||
public async deleteForRequest(requestId: number): Promise<void> {
|
public async deleteForRequest(requestId: number): Promise<void> {
|
||||||
const rows = await this.getForRequest(requestId);
|
const rows = await this.getForRequest(requestId);
|
||||||
for (const row of rows) {
|
if (rows.length === 0) return;
|
||||||
await this.list().items.getById(row.id).delete();
|
|
||||||
}
|
// writeRoute вызывает это перед перезаписью (пересохранение черновика,
|
||||||
|
// повторная отправка) — тот же per-row POST/DELETE в цикле, что и
|
||||||
|
// раньше в createSteps, и то же решение: один batch вместо N запросов.
|
||||||
|
const [batchedSP, execute] = getSP().batched();
|
||||||
|
const batchedItems = batchedSP.web.lists.getByTitle(this.listTitle).items;
|
||||||
|
rows.forEach((row) => {
|
||||||
|
// void — по той же причине, что и в createSteps выше.
|
||||||
|
void batchedItems.getById(row.id).delete();
|
||||||
|
});
|
||||||
|
await execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Id текущего пользователя на сайте (для сравнения с полем «Согласующий»).
|
// Id текущего пользователя на сайте (для сравнения с полем «Согласующий»).
|
||||||
|
|||||||
Reference in New Issue
Block a user