батчинг
This commit is contained in:
@@ -5,6 +5,7 @@ import { IList } from '@pnp/sp/lists';
|
||||
import '@pnp/sp/items';
|
||||
import '@pnp/sp/site-users/web';
|
||||
import '@pnp/sp/profiles';
|
||||
import '@pnp/sp/batching';
|
||||
import { getImpersonatedEmail } from '../impersonation';
|
||||
import { IApprovalRow } from './models/IApprovalRow';
|
||||
import { IMatrixRow } from './models/IMatrixRow';
|
||||
@@ -106,11 +107,31 @@ export class ApprovalListService {
|
||||
);
|
||||
}
|
||||
|
||||
for (const { a, order } of withOrder.filter((x) => !!x.a.email)) {
|
||||
const approverId = await this.resolveUserId(a.email);
|
||||
await this.list().items.add({
|
||||
const toWrite = withOrder.filter((x) => !!x.a.email);
|
||||
if (toWrite.length === 0) return;
|
||||
|
||||
// Резолв 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,
|
||||
[`${FIELDS.approver}Id`]: approverId,
|
||||
[`${FIELDS.approver}Id`]: approverIds[i],
|
||||
[FIELDS.status]: status,
|
||||
[`${FIELDS.ticket}Id`]: requestId,
|
||||
[FIELDS.order]: order,
|
||||
@@ -120,7 +141,8 @@ export class ApprovalListService {
|
||||
[FIELDS.slaHours]: a.slaHours ?? null,
|
||||
[FIELDS.askOverdueReason]: a.askOverdueReason ?? null,
|
||||
});
|
||||
}
|
||||
});
|
||||
await execute();
|
||||
}
|
||||
|
||||
// Продвигает очередь: среди ещё не активных строк со статусом «Ждёт очереди»
|
||||
@@ -344,9 +366,18 @@ export class ApprovalListService {
|
||||
// Удаляет все строки согласования по заявке (при возврате/повторной отправке).
|
||||
public async deleteForRequest(requestId: number): Promise<void> {
|
||||
const rows = await this.getForRequest(requestId);
|
||||
for (const row of rows) {
|
||||
await this.list().items.getById(row.id).delete();
|
||||
}
|
||||
if (rows.length === 0) return;
|
||||
|
||||
// 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 текущего пользователя на сайте (для сравнения с полем «Согласующий»).
|
||||
|
||||
Reference in New Issue
Block a user