szdl-utils-kit 0.3.23 → 0.3.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Readme.md CHANGED
@@ -187,7 +187,9 @@ await worker.init();
187
187
  - `bx` – инициализированный экземпляр `BxBoot`, используемый для работы с REST;
188
188
  - `appFunc` – функция, которая должна выполниться в «активном» табе;
189
189
  - `users` – подготовленные данные (если не переданы, будут запрошены через REST);
190
- - `continueBackground` – опциональная функция-условие (`(worker) => boolean | Promise<boolean)`), которая определяет, можно ли запускать воркер. Должна вернуть `true`, чтобы продолжить цикл. По умолчанию всегда возвращает `true`.
190
+ - `continueBackground` – опциональная функция-условие (`(worker) => boolean | Promise<boolean)`), которая определяет, можно ли запускать воркер. Должна вернуть `true`, чтобы продолжить цикл. По умолчанию всегда возвращает `true`;
191
+ - `timing` – объект с таймингами poll-цикла, подтверждения лидерства и разнесённого старта приложений (см. [Тайминги](#тайминги-timing)). Можно передать только нужные поля — остальные возьмутся из `DEFAULT_BACKGROUND_WORKER_TIMING`;
192
+ - `coordinationScope` – область координации лидера и пула вкладок (см. [Область координации](#область-координации-coordinationscope)). По умолчанию `'user'`.
191
193
 
192
194
  ```ts
193
195
  const worker = new BackgroundWorker({
@@ -206,6 +208,111 @@ const worker = new BackgroundWorker({
206
208
  });
207
209
  ```
208
210
 
211
+ #### Область координации (`coordinationScope`)
212
+
213
+ Передаётся строкой: `'user'` или `'portal'`. Другие значения игнорируются с предупреждением в консоль, используется `'user'`.
214
+
215
+ | Значение | Поведение |
216
+ |----------|-----------|
217
+ | `'user'` (по умолчанию) | Один запуск `appFunc` одновременно **на пользователя**. Вкладки разных пользователей не конкурируют. |
218
+ | `'portal'` | Один запуск `appFunc` одновременно **на портал**. Все пользователи в общем пуле вкладок; лидер один на всё приложение. |
219
+
220
+ **Как это работает:**
221
+
222
+ - В режиме `'user'` записи в entity хранятся с `NAME = userId`, Web Lock тоже per-user.
223
+ - В режиме `'portal'` все вкладки пишутся с общим ключом `NAME = {appCodeName}:portal`, Web Lock — per-portal (per-app).
224
+ - В данных вкладки всегда сохраняется `userId` — в portal-режиме видно, у кого открыта вкладка, хотя `appFunc` выполняется только у лидера.
225
+ - `setBackgroundWorkerAll` в portal-режиме привязывает только общую встройку `PAGE_BACKGROUND_WORKER` и отвязывает персональные (`USER_ID=…`).
226
+
227
+ ```ts
228
+ const worker = new BackgroundWorker({
229
+ bx,
230
+ appFunc: async () => {
231
+ console.log("background job started (once per portal)");
232
+ },
233
+ coordinationScope: "portal",
234
+ });
235
+ await worker.init();
236
+ ```
237
+
238
+ #### Тайминги (`timing`)
239
+
240
+ Экспортируются `DEFAULT_BACKGROUND_WORKER_TIMING` и `resolveBackgroundWorkerTiming` — удобно собирать конфиг заранее или переопределять отдельные поля.
241
+
242
+ ```ts
243
+ import {
244
+ BackgroundWorker,
245
+ DEFAULT_BACKGROUND_WORKER_TIMING,
246
+ resolveBackgroundWorkerTiming,
247
+ } from "szdl-utils-kit";
248
+
249
+ const timing = resolveBackgroundWorkerTiming({
250
+ startDelayMs: 10_000,
251
+ leaderConfirmDelayMs: 10_000,
252
+ });
253
+
254
+ const worker = new BackgroundWorker({ bx, appFunc, timing });
255
+ ```
256
+
257
+ **Поля объекта `timing`:**
258
+
259
+ | Поле | По умолчанию | Назначение |
260
+ |------|--------------|------------|
261
+ | `startDelayMs` | `0` | Пауза перед первым poll-тиком. Разносит старт разных приложений (один апп — через 20 с, другой — через 4–5 мин). |
262
+ | `pollIntervalMs` | `60_000` | Базовый интервал фонового poll-цикла (обновление `lastActive`, выбор лидера, очистка мёртвых вкладок). |
263
+ | `pollIntervalJitterMs` | `30_000` | Случайная добавка к `pollIntervalMs`. Итоговый интервал: от `pollIntervalMs` до `pollIntervalMs + pollIntervalJitterMs` (по умолчанию 1–1,5 мин). |
264
+ | `leaderConfirmDelayMs` | `60_000` | Пауза после захвата Web Lock перед повторной проверкой лидерства и вызовом `appFunc`. Защита от гонки между вкладками. |
265
+ | `activeMaxPauseMs` | `180_000` | Порог «мёртвой» вкладки: если `lastActive` не обновлялся дольше — запись удаляется из entity. Должен быть **больше** `startDelayMs + leaderConfirmDelayMs`, иначе вкладка может удалиться во время пауз перед стартом. |
266
+ | `quickCleanupThresholdMs` | `300_000` | Отдельный порог для агрессивной очистки, когда достигнут лимит вкладок (`maxTabs`). |
267
+ | `leaderHeartbeatMs` | `null` | Интервал обновления `lastActive` лидером во время `appFunc`. Если не задан — вычисляется автоматически из `pollInterval` и `activeMaxPauseMs`. |
268
+
269
+ **Как устроен старт (без лишних раундов):**
270
+
271
+ 1. Регистрация вкладки в entity.
272
+ 2. Пауза `startDelayMs` (если задана).
273
+ 3. Poll-тик: выбор лидера по entity (самая старая вкладка).
274
+ 4. Если текущая вкладка — лидер: захват Web Lock → пауза `leaderConfirmDelayMs` → повторная проверка лидера → `appFunc`.
275
+ 5. Далее poll-цикл продолжается с интервалом `pollIntervalMs` … `+ pollIntervalJitterMs`.
276
+
277
+ **Пример: старт через ~20 секунд**
278
+
279
+ ```ts
280
+ const START_DELAY_MS = 10_000;
281
+ const LEADER_CONFIRM_MS = 10_000;
282
+
283
+ const worker = new BackgroundWorker({
284
+ bx,
285
+ appFunc: async () => {
286
+ console.log("background job started");
287
+ },
288
+ timing: {
289
+ ...DEFAULT_BACKGROUND_WORKER_TIMING,
290
+ startDelayMs: START_DELAY_MS,
291
+ leaderConfirmDelayMs: LEADER_CONFIRM_MS,
292
+ activeMaxPauseMs: Math.max(
293
+ 60_000,
294
+ (START_DELAY_MS + LEADER_CONFIRM_MS) * 3,
295
+ ),
296
+ },
297
+ });
298
+ ```
299
+
300
+ **Пример: отложенный старт (~4–5 минут)**
301
+
302
+ ```ts
303
+ const worker = new BackgroundWorker({
304
+ bx,
305
+ appFunc: async () => {
306
+ /* ... */
307
+ },
308
+ timing: {
309
+ ...DEFAULT_BACKGROUND_WORKER_TIMING,
310
+ startDelayMs: 4 * 60_000,
311
+ leaderConfirmDelayMs: 60_000,
312
+ },
313
+ });
314
+ ```
315
+
209
316
  Методы:
210
317
 
211
318
  - **`init`** – регистрирует бек-встройку для текущего пользователя, создаёт запись текущего таба и запускает цикл наблюдения.
@@ -227,7 +334,7 @@ const formatted = tempus().format("%Y-%m-%d");
227
334
 
228
335
  - `types/batch.d.ts` – детальное описание Batch;
229
336
  - `types/bx-boot.d.ts`, `types/bx-helper.d.ts`, `types/bx-logger.d.ts`;
230
- - `types/background-worker.d.ts`.
337
+ - `types/background-worker.d.ts` – в том числе `BackgroundWorkerTiming`, `DEFAULT_BACKGROUND_WORKER_TIMING`.
231
338
 
232
339
  ## Разработка и публикация
233
340