@io-orkes/conductor-javascript 1.2.1-rc.1 → 1.2.1-rc.3

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/dist/index.mjs CHANGED
@@ -2188,14 +2188,17 @@ var BaseHttpRequest = class {
2188
2188
 
2189
2189
  // src/task/Poller.ts
2190
2190
  var Poller = class {
2191
- constructor(pollFunction, pollerOptions, logger) {
2192
- this.concurrentCalls = [];
2193
- this.pollFunction = async () => {
2191
+ constructor(pollerId, pollFunction, performWorkFunction, pollerOptions, logger) {
2192
+ this.performWorkFunction = async () => {
2194
2193
  };
2195
2194
  this.polling = false;
2195
+ this._tasksInProcess = 0;
2196
+ this._counterAtO = 0;
2197
+ this._pollerId = "";
2196
2198
  this.options = {
2197
- pollInterval: 1e3,
2198
- concurrency: 1
2199
+ pollInterval: 100,
2200
+ concurrency: 1,
2201
+ warnAtO: 100
2199
2202
  };
2200
2203
  this.logger = noopLogger;
2201
2204
  /**
@@ -2205,78 +2208,69 @@ var Poller = class {
2205
2208
  if (this.polling) {
2206
2209
  throw new Error("Runner is already started");
2207
2210
  }
2208
- return this.poll();
2211
+ this._tasksInProcess = 0;
2212
+ this.polling = true;
2213
+ this.poll();
2209
2214
  };
2210
2215
  /**
2211
2216
  * Stops Polling for work
2212
2217
  */
2213
2218
  this.stopPolling = async () => {
2214
- await Promise.all(this.concurrentCalls.map((call) => call.stop()));
2215
2219
  this.polling = false;
2220
+ clearTimeout(this.timeoutHandler);
2216
2221
  };
2217
- this.poll = async () => {
2218
- if (!this.polling) {
2219
- this.polling = true;
2220
- for (let i = 0; i < this.options.concurrency; i++) {
2221
- this.concurrentCalls.push(this.singlePoll());
2222
- }
2223
- }
2222
+ this.performWork = async (work) => {
2223
+ await this.performWorkFunction(work);
2224
+ this._tasksInProcess--;
2224
2225
  };
2225
- this.singlePoll = () => {
2226
- let poll = this.polling;
2227
- let timeout;
2228
- const pollingCall = async () => {
2229
- while (poll) {
2230
- await this.pollFunction();
2231
- await new Promise(
2232
- (r) => poll ? timeout = setTimeout(() => r(true), this.options.pollInterval) : r(true)
2226
+ this.poll = async () => {
2227
+ while (this.isPolling) {
2228
+ try {
2229
+ const count = Math.max(
2230
+ 0,
2231
+ this.options.concurrency - this._tasksInProcess
2233
2232
  );
2233
+ if (count == 0) {
2234
+ this.logger.debug(
2235
+ "Max in process reached, Will skip polling for " + this._pollerId
2236
+ );
2237
+ this._counterAtO++;
2238
+ if (this._counterAtO > (this.options.warnAtO ?? 100)) {
2239
+ this.logger.info(
2240
+ `Not polling anything because in process tasks is maxed as concurrency level. ${this._pollerId}`
2241
+ );
2242
+ }
2243
+ } else {
2244
+ this._counterAtO = 0;
2245
+ const tasksResult = await this.pollFunction(count);
2246
+ this._tasksInProcess = this._tasksInProcess + (tasksResult ?? []).length;
2247
+ tasksResult.forEach(this.performWork);
2248
+ }
2249
+ } catch (e) {
2250
+ this.logger.error(`Error polling for tasks: ${e.message}`, e);
2234
2251
  }
2235
- };
2236
- return {
2237
- promise: pollingCall(),
2238
- stop: () => new Promise((r) => {
2239
- clearTimeout(timeout);
2240
- poll = false;
2241
- this.logger.debug("stopping single poll call");
2242
- r(true);
2243
- })
2244
- };
2252
+ await new Promise(
2253
+ (r) => this.isPolling ? this.timeoutHandler = setTimeout(
2254
+ () => r(true),
2255
+ this.options.pollInterval
2256
+ ) : r(true)
2257
+ );
2258
+ }
2245
2259
  };
2260
+ this._pollerId = pollerId;
2246
2261
  this.pollFunction = pollFunction;
2262
+ this.performWorkFunction = performWorkFunction;
2247
2263
  this.options = { ...this.options, ...pollerOptions };
2248
2264
  this.logger = logger || noopLogger;
2249
2265
  }
2250
2266
  get isPolling() {
2251
2267
  return this.polling;
2252
2268
  }
2253
- /**
2254
- * adds or shuts down concurrent calls based on the concurrency setting
2255
- * @param concurrency
2256
- */
2257
- updateConcurrency(concurrency) {
2258
- if (concurrency > 0 && concurrency !== this.options.concurrency) {
2259
- if (concurrency < this.options.concurrency) {
2260
- const result = this.concurrentCalls.splice(
2261
- 0,
2262
- this.options.concurrency - concurrency
2263
- );
2264
- result.forEach((call) => {
2265
- call.stop();
2266
- this.logger.debug("stopping some spawned calls");
2267
- });
2268
- } else {
2269
- for (let i = 0; i < concurrency - this.options.concurrency; i++) {
2270
- this.concurrentCalls.push(this.singlePoll());
2271
- this.logger.debug("spawning additional poll calls");
2272
- }
2273
- }
2274
- this.options.concurrency = concurrency;
2275
- }
2269
+ get tasksInProcess() {
2270
+ return this._tasksInProcess;
2276
2271
  }
2277
2272
  updateOptions(options) {
2278
2273
  const newOptions = { ...this.options, ...options };
2279
- this.updateConcurrency(newOptions.concurrency);
2280
2274
  this.options = newOptions;
2281
2275
  }
2282
2276
  };
@@ -2286,6 +2280,13 @@ var DEFAULT_ERROR_MESSAGE = "An unknown error occurred";
2286
2280
  var MAX_RETRIES = 3;
2287
2281
  var noopErrorHandler = (__error) => {
2288
2282
  };
2283
+ var defaultRunnerOptions = {
2284
+ workerID: "",
2285
+ pollInterval: 100,
2286
+ domain: void 0,
2287
+ concurrency: 1,
2288
+ batchPollingTimeout: 100
2289
+ };
2289
2290
  var TaskRunner = class {
2290
2291
  constructor({
2291
2292
  worker,
@@ -2299,6 +2300,9 @@ var TaskRunner = class {
2299
2300
  */
2300
2301
  this.startPolling = () => {
2301
2302
  this.poller.startPolling();
2303
+ this.logger.info(
2304
+ `TaskWorker ${this.worker.taskDefName} initialized with concurrency of ${this.poller.options.concurrency} and poll interval of ${this.poller.options.pollInterval}`
2305
+ );
2302
2306
  };
2303
2307
  /**
2304
2308
  * Stops Polling for work
@@ -2306,23 +2310,17 @@ var TaskRunner = class {
2306
2310
  this.stopPolling = async () => {
2307
2311
  await this.poller.stopPolling();
2308
2312
  };
2309
- this.pollAndExecute = async () => {
2310
- try {
2311
- const { workerID } = this.options;
2312
- const task = await this.taskResource.poll(
2313
- this.worker.taskDefName,
2314
- workerID,
2315
- this.worker.domain ?? this.options.domain
2316
- );
2317
- if (task && task.taskId) {
2318
- await this.executeTask(task);
2319
- } else {
2320
- this.logger.debug(`No tasks for ${this.worker.taskDefName}`);
2321
- }
2322
- } catch (unknownError) {
2323
- this.handleUnknownError(unknownError);
2324
- this.errorHandler(unknownError);
2325
- }
2313
+ this.batchPoll = async (count) => {
2314
+ const { workerID } = this.options;
2315
+ const tasks = await this.taskResource.batchPoll(
2316
+ this.worker.taskDefName,
2317
+ workerID,
2318
+ this.worker.domain ?? this.options.domain,
2319
+ count,
2320
+ this.options.batchPollingTimeout ?? 100
2321
+ // default batch poll defined in the method
2322
+ );
2323
+ return tasks;
2326
2324
  };
2327
2325
  this.updateTaskWithRetry = async (task, taskResult) => {
2328
2326
  let retryCount = 0;
@@ -2381,11 +2379,16 @@ var TaskRunner = class {
2381
2379
  this.taskResource = taskResource;
2382
2380
  this.logger = logger;
2383
2381
  this.worker = worker;
2384
- this.options = options;
2382
+ this.options = { ...defaultRunnerOptions, ...options };
2385
2383
  this.errorHandler = errorHandler;
2386
2384
  this.poller = new Poller(
2387
- this.pollAndExecute,
2388
- { concurrency: options.concurrency, pollInterval: options.pollInterval },
2385
+ worker.taskDefName,
2386
+ this.batchPoll,
2387
+ this.executeTask,
2388
+ {
2389
+ concurrency: worker.concurrency ?? options.concurrency,
2390
+ pollInterval: worker.pollInterval ?? options.pollInterval
2391
+ },
2389
2392
  this.logger
2390
2393
  );
2391
2394
  }
@@ -2398,6 +2401,9 @@ var TaskRunner = class {
2398
2401
  concurrency: newOptions.concurrency,
2399
2402
  pollInterval: newOptions.pollInterval
2400
2403
  });
2404
+ this.logger.info(
2405
+ `TaskWorker ${this.worker.taskDefName} configuration updated with concurrency of ${this.poller.options.concurrency} and poll interval of ${this.poller.options.pollInterval}`
2406
+ );
2401
2407
  this.options = newOptions;
2402
2408
  }
2403
2409
  get getOptions() {
@@ -2409,24 +2415,36 @@ var TaskRunner = class {
2409
2415
  import os from "os";
2410
2416
  var defaultManagerOptions = {
2411
2417
  workerID: "",
2412
- pollInterval: 1e3,
2418
+ pollInterval: 100,
2413
2419
  domain: void 0,
2414
- concurrency: 1
2420
+ concurrency: 1,
2421
+ batchPollingTimeout: 100
2415
2422
  };
2416
2423
  function workerId(options) {
2417
2424
  return options.workerID ?? os.hostname();
2418
2425
  }
2419
2426
  var TaskManager = class {
2420
2427
  constructor(client, workers, config = {}) {
2421
- this.tasks = {};
2428
+ this.workerRunners = /* @__PURE__ */ new Map();
2422
2429
  this.polling = false;
2423
2430
  this.workerManagerWorkerOptions = (worker) => {
2424
2431
  return {
2425
2432
  ...this.options,
2426
2433
  concurrency: worker.concurrency ?? this.options.concurrency,
2434
+ pollInterval: worker.pollInterval ?? this.options.pollInterval,
2427
2435
  domain: worker.domain ?? this.options.domain
2428
2436
  };
2429
2437
  };
2438
+ this.updatePollingOptionForWorker = (workerTaskDefName, options) => {
2439
+ const maybeRunner = this.workerRunners.get(workerTaskDefName);
2440
+ if (maybeRunner != null) {
2441
+ maybeRunner.updateOptions(options);
2442
+ } else {
2443
+ this.logger.info(
2444
+ `No runner found for worker with taskDefName: ${workerTaskDefName}`
2445
+ );
2446
+ }
2447
+ };
2430
2448
  /**
2431
2449
  * new options will get merged to existing options
2432
2450
  * @param options new options to update polling options
@@ -2437,24 +2455,30 @@ var TaskManager = class {
2437
2455
  ...this.workerManagerWorkerOptions(worker),
2438
2456
  ...options
2439
2457
  };
2440
- const runners = this.tasks[worker.taskDefName];
2441
- runners.forEach((runner) => {
2442
- runner.updateOptions(newOptions);
2443
- });
2458
+ this.updatePollingOptionForWorker(worker.taskDefName, newOptions);
2444
2459
  });
2445
2460
  this.options.concurrency = options.concurrency ?? this.options.concurrency;
2446
2461
  this.options.pollInterval = options.pollInterval ?? this.options.pollInterval;
2447
2462
  };
2463
+ this.sanityCheck = () => {
2464
+ if (this.workers.length === 0) {
2465
+ throw new Error("No workers supplied to TaskManager");
2466
+ }
2467
+ const workerIDs = /* @__PURE__ */ new Set();
2468
+ for (const item of this.workers) {
2469
+ if (workerIDs.has(item.taskDefName)) {
2470
+ throw new Error(`Duplicate worker taskDefName: ${item.taskDefName}`);
2471
+ }
2472
+ workerIDs.add(item.taskDefName);
2473
+ }
2474
+ };
2448
2475
  /**
2449
2476
  * Start polling for tasks
2450
2477
  */
2451
2478
  this.startPolling = () => {
2479
+ this.sanityCheck();
2452
2480
  this.workers.forEach((worker) => {
2453
- this.tasks[worker.taskDefName] = [];
2454
2481
  const options = this.workerManagerWorkerOptions(worker);
2455
- this.logger.debug(
2456
- `Starting taskDefName=${worker.taskDefName} concurrency=${options.concurrency} domain=${options.domain}`
2457
- );
2458
2482
  const runner = new TaskRunner({
2459
2483
  worker,
2460
2484
  options,
@@ -2463,7 +2487,7 @@ var TaskManager = class {
2463
2487
  onError: this.errorHandler
2464
2488
  });
2465
2489
  runner.startPolling();
2466
- this.tasks[worker.taskDefName].push(runner);
2490
+ this.workerRunners.set(worker.taskDefName, runner);
2467
2491
  });
2468
2492
  this.polling = true;
2469
2493
  };
@@ -2471,11 +2495,10 @@ var TaskManager = class {
2471
2495
  * Stops polling for tasks
2472
2496
  */
2473
2497
  this.stopPolling = async () => {
2474
- for (const taskType in this.tasks) {
2475
- await Promise.all(
2476
- this.tasks[taskType].map((runner) => runner.stopPolling())
2477
- );
2478
- this.tasks[taskType] = [];
2498
+ for (const [workerTaskDefName, runner] of this.workerRunners) {
2499
+ this.logger.debug(`Stopping taskDefName=${workerTaskDefName}`);
2500
+ await runner.stopPolling();
2501
+ this.workerRunners.delete(workerTaskDefName);
2479
2502
  }
2480
2503
  this.polling = false;
2481
2504
  };