psdev-task-manager 2.0.5 → 2.0.6

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.
@@ -3,10 +3,7 @@ name: Update Sites After Release Main
3
3
  on:
4
4
  push:
5
5
  branches:
6
- - main
7
- pull_request:
8
- branches:
9
- - main
6
+ - main
10
7
  workflow_dispatch:
11
8
 
12
9
  permissions:
@@ -14,17 +11,17 @@ permissions:
14
11
  packages: write
15
12
 
16
13
  jobs:
17
- update-sites:
18
- uses: psdevteamenterprise/ci-workflows/.github/workflows/publish-and-notify.yml@main
19
- with:
20
- npm_packages_to_update: "[{repo: 'Hisense-Wix/velo-npm'}]"
21
- sites_to_update: "[{repo: 'psdevteamenterprise/external-template', secret: 'WIX_SR_API_KEY'},
22
- {repo: 'psdevteamenterprise/internal', secret: 'WIX_SR_API_KEY'},
23
- {repo: 'psdevteamenterprise/tests-site', secret: 'WIX_PS_API_KEY'}]"
24
- secrets:
25
- GH_TOKEN: ${{ secrets.MY_GITHUB_TOKEN }}
26
- NPM_TOKEN: ${{ secrets.NPM_TOKEN_PUBLISH }}
27
- GH_APP_ID: ${{ secrets.GH_APP_ID }}
28
- GH_APP_PRIVATE_KEY: ${{ secrets.GH_APP_PRIVATE_KEY }}
29
- WIX_SR_API_KEY: ${{secrets.WIX_SR_API_KEY}}
30
- WIX_PS_API_KEY: ${{secrets.WIX_PS_API_KEY}}
14
+ update-sites:
15
+ uses: psdevteamenterprise/ci-workflows/.github/workflows/update-and-notify.yml@main
16
+ with:
17
+ npm_packages_to_update: "[{repo: 'Hisense-Wix/velo-npm'}]"
18
+ sites_to_update: "[{repo: 'psdevteamenterprise/external-template', secret: 'WIX_SR_API_KEY'},
19
+ {repo: 'psdevteamenterprise/internal', secret: 'WIX_SR_API_KEY'},
20
+ {repo: 'psdevteamenterprise/tests-site', secret: 'WIX_PS_API_KEY'}]"
21
+ secrets:
22
+ GH_TOKEN: ${{ secrets.MY_GITHUB_TOKEN }}
23
+ NPM_TOKEN: ${{ secrets.NPM_TOKEN_PUBLISH }}
24
+ GH_APP_ID: ${{ secrets.GH_APP_ID }}
25
+ GH_APP_PRIVATE_KEY: ${{ secrets.GH_APP_PRIVATE_KEY }}
26
+ WIX_SR_API_KEY: ${{secrets.WIX_SR_API_KEY}}
27
+ WIX_PS_API_KEY: ${{secrets.WIX_PS_API_KEY}}
@@ -0,0 +1,7 @@
1
+ node_modules
2
+ dist
3
+ build
4
+ coverage
5
+ *.min.js
6
+ package-lock.json
7
+
@@ -0,0 +1,16 @@
1
+ {
2
+ "singleQuote": true,
3
+ "trailingComma": "es5",
4
+ "printWidth": 100,
5
+ "tabWidth": 2,
6
+ "semi": true,
7
+ "bracketSpacing": true,
8
+ "bracketSameLine": false,
9
+ "arrowParens": "avoid",
10
+ "endOfLine": "lf",
11
+ "quoteProps": "as-needed",
12
+ "jsxSingleQuote": false,
13
+ "requirePragma": false,
14
+ "insertPragma": false,
15
+ "proseWrap": "preserve"
16
+ }
package/README.md CHANGED
@@ -1,2 +1,3 @@
1
1
  # task-manager
2
+
2
3
  Task manager library
@@ -7,5 +7,4 @@ module.exports = {
7
7
  ...require('./taskManager'),
8
8
  ...require('./utils'),
9
9
  ...require('./tasks'),
10
-
11
10
  };
@@ -2,5 +2,5 @@ module.exports = {
2
2
  ...require('./handler'),
3
3
  ...require('./childScheduler'),
4
4
  ...require('./parentStatusManager'),
5
- ...require('./utils')
5
+ ...require('./utils'),
6
6
  };
@@ -1,6 +1,6 @@
1
- const { withDuration } = require('psdev-utils');
1
+ const { withDuration, withSuccessRateLogs } = require('psdev-utils');
2
2
 
3
- const { TASK_STATUS, CRON_JOB_MAX_DURATION_SEC } = require('./consts');
3
+ const { TASK_STATUS, CRON_JOB_MAX_DURATION_SEC, TASK_MAX_TRIES } = require('./consts');
4
4
  const { scheduleChildTasksAndUpdateParent } = require('./parentChildTasks/handler');
5
5
  const {
6
6
  saveTaskResultToAdditionalCollection,
@@ -17,7 +17,7 @@ const {
17
17
  } = require('./utils');
18
18
 
19
19
  function taskManager() {
20
- const processTask = (task, tasksConfig) =>
20
+ const processTaskWithDuration = (task, tasksConfig) =>
21
21
  withDuration(
22
22
  'processTask',
23
23
  async () => {
@@ -73,24 +73,32 @@ function taskManager() {
73
73
  if (saveResults) {
74
74
  await saveTaskResultToAdditionalCollection(task, TASK_STATUS.FAILED, { error });
75
75
  }
76
- throw new Error(errMsg);
76
+ const isFailedAfterAllRetries = amountOfRetries >= TASK_MAX_TRIES;
77
+ if (isFailedAfterAllRetries) {
78
+ //Only throw error if task is permanently failed, otherwise we have retry mechanism
79
+ throw new Error(errMsg);
80
+ }
77
81
  }
78
82
  },
79
83
  console
80
84
  );
85
+ const processTask = (...args) => {
86
+ const requestName = `processTask_${args[0].name}`; //To get success rate analysis per task
87
+ return withSuccessRateLogs(requestName, () => processTaskWithDuration(...args));
88
+ };
81
89
  /**
82
90
  * @description Processing tasks based on how many the cron job tick can handle and running them sequentially to be as safe as possible
83
91
  * */
84
92
  const processTasksBasedOnVeloLimit = async (scheduledTasks, tasksConfig) => {
85
93
  console.log(
86
- `processTasksBasedOnVeloLimit: ${JSON.stringify(scheduledTasks)} ${JSON.stringify(tasksConfig)}`
94
+ `processTasksBasedOnVeloLimit: scheduledTasks count: ${scheduledTasks.length} tasksConfig: ${JSON.stringify(tasksConfig)}`
87
95
  );
88
96
  const toProcessTasks = getTasksToProcess({
89
97
  scheduledTasks,
90
98
  tasksConfig,
91
99
  maxDuration: CRON_JOB_MAX_DURATION_SEC,
92
100
  });
93
- console.log(`processTasksBasedOnVeloLimit: toProcessTasks: ${JSON.stringify(toProcessTasks)}`);
101
+ console.log(`processTasksBasedOnVeloLimit: toProcessTasks count: ${toProcessTasks.length}`);
94
102
  console.log(
95
103
  `[processTasksBasedOnVeloLimit] started processing: ${toProcessTasks.length} tasks`
96
104
  );
@@ -113,7 +121,7 @@ function taskManager() {
113
121
  const runScheduledTasks = async tasksConfig => {
114
122
  try {
115
123
  const scheduledTasks = await getScheduledTasks();
116
- console.log(`runScheduledTasks: scheduledTasks: ${JSON.stringify(scheduledTasks)}`);
124
+ console.log(`runScheduledTasks: scheduledTasks count: ${scheduledTasks.length}`);
117
125
  console.log(`runScheduledTasks: tasksConfig: ${JSON.stringify(tasksConfig)}`);
118
126
  if (scheduledTasks.length) {
119
127
  await processTasksBasedOnVeloLimit(scheduledTasks, tasksConfig);
@@ -1,29 +1,29 @@
1
1
  const TASKS = {
2
- TEST_TASK: {
3
- name: 'TestTask',
4
- getIdentifier: (task) => (task),
5
- process: (task) => {
6
- const data = task.data || {};
7
- let error;
8
- if (data.retries){
9
- error = task.error ? Number(task.error) - 1 : data.retries - 1;
10
- }
11
- if (data.shouldFail && (!error || error > 0)){
12
- throw new Error(error?.toString() || 'Test error');
13
- }
14
- return 'test';
15
- },
16
- shouldSkipCheck: (task) => task.data.shouldSkip,
17
- estimatedDurationSec:2,
2
+ TEST_TASK: {
3
+ name: 'TestTask',
4
+ getIdentifier: task => task,
5
+ process: task => {
6
+ const data = task.data || {};
7
+ let error;
8
+ if (data.retries) {
9
+ error = task.error ? Number(task.error) - 1 : data.retries - 1;
10
+ }
11
+ if (data.shouldFail && (!error || error > 0)) {
12
+ throw new Error(error?.toString() || 'Test error');
13
+ }
14
+ return 'test';
18
15
  },
19
- BAD_TASK: {
20
- name: 'BadTask',
21
- getIdentifier: () => true,
22
- process: () => 'test',
23
- shouldSkipCheck: () => false,
24
- },
25
- };
16
+ shouldSkipCheck: task => task.data.shouldSkip,
17
+ estimatedDurationSec: 2,
18
+ },
19
+ BAD_TASK: {
20
+ name: 'BadTask',
21
+ getIdentifier: () => true,
22
+ process: () => 'test',
23
+ shouldSkipCheck: () => false,
24
+ },
25
+ };
26
26
 
27
- module.exports = {
28
- TASKS,
29
- };
27
+ module.exports = {
28
+ TASKS,
29
+ };
@@ -44,7 +44,7 @@ async function createCollectionIfMissing(
44
44
  if (collectionType === 'singleItem') {
45
45
  createDataCollectionOptions.plugins = [
46
46
  {
47
- type: "SINGLE_ITEM",
47
+ type: 'SINGLE_ITEM',
48
48
  singleItemOptions: {},
49
49
  },
50
50
  ];
@@ -169,18 +169,30 @@ const isParentTask = (task, taskConfig) => {
169
169
  };
170
170
  const filterScheduledTasksByStatus = (tasks, tasksConfig) => {
171
171
  console.log(
172
- `filterScheduledTasksByStatus: ${JSON.stringify(tasks)} ${JSON.stringify(tasksConfig)}`
172
+ `filterScheduledTasksByStatus: tasks count: ${tasks.length} tasksConfig: ${JSON.stringify(tasksConfig)}`
173
173
  );
174
- const filtered = tasks.filter(task => {
175
- if (task.status === TASK_STATUS.IN_PROGRESS) {
176
- //Only include parent tasks that are in progress
177
- console.log(`filterScheduledTasksByStatus: task: ${JSON.stringify(task)}`);
178
- console.log(`filterScheduledTasksByStatus: tasksConfig: ${JSON.stringify(tasksConfig)}`);
179
- return isParentTask(task, tasksConfig[task.name]);
174
+ const shouldIncludeTask = (task, taskConfig) => {
175
+ console.log(`filterScheduledTasksByStatus: task: ${JSON.stringify(task)}`);
176
+ console.log(`filterScheduledTasksByStatus: taskConfig: ${JSON.stringify(taskConfig)}`);
177
+ const { status } = task;
178
+ if (status === TASK_STATUS.IN_PROGRESS) {
179
+ //Only include parent tasks that are in progress, to continue running next children
180
+ return isParentTask(task, taskConfig);
180
181
  }
182
+ //TODO: need to rethink of this as some parent tasks we use only to schedule children,
183
+ // if (status === TASK_STATUS.FAILED) {
184
+ // // Exclude if it's a parent task, if parent task failed, we don't retry it anymore
185
+ // return !isParentTask(task, taskConfig);
186
+ // }
187
+ // // Include if status is PENDING
188
+ // return status === TASK_STATUS.PENDING;
181
189
  return [TASK_STATUS.PENDING, TASK_STATUS.FAILED].includes(task.status);
190
+ };
191
+ const filtered = tasks.filter(task => {
192
+ const taskConfig = tasksConfig[task.name];
193
+ return shouldIncludeTask(task, taskConfig);
182
194
  });
183
- console.log(`filterScheduledTasksByStatus: filtered: ${JSON.stringify(filtered)}`);
195
+ console.log(`filterScheduledTasksByStatus: filtered count: ${filtered.length}`);
184
196
  return filtered;
185
197
  };
186
198
  const getScheduledTasks = async () => {
@@ -221,12 +233,16 @@ const getTaskScheduledChildren = async parentTaskId => {
221
233
  };
222
234
 
223
235
  const getTasksToProcess = ({ scheduledTasks, tasksConfig, maxDuration }) => {
224
- console.log('getTasksToProcess:', { scheduledTasks, tasksConfig, maxDuration });
236
+ console.log('getTasksToProcess:', {
237
+ scheduledTasksCount: scheduledTasks.length,
238
+ tasksConfig,
239
+ maxDuration,
240
+ });
225
241
  const tasksToProcess = [];
226
242
  let totalDuration = 0;
227
243
  console.log(`tasksConfig is : ${JSON.stringify(tasksConfig)}`);
228
244
  const filteredScheduledTasks = filterScheduledTasksByStatus(scheduledTasks, tasksConfig);
229
- console.log(`filteredScheduledTasks is : ${JSON.stringify(filteredScheduledTasks)}`);
245
+ console.log(`filteredScheduledTasks count : ${filteredScheduledTasks.length}`);
230
246
  for (const task of filteredScheduledTasks) {
231
247
  console.log(`task is : ${JSON.stringify(task)}`);
232
248
  const taskConfig = getTaskConfig(task.name, tasksConfig);
@@ -243,7 +259,7 @@ const getTasksToProcess = ({ scheduledTasks, tasksConfig, maxDuration }) => {
243
259
  totalDuration += buffered;
244
260
  tasksToProcess.push(task);
245
261
  }
246
- console.log('getTasksToProcess: tasksToProcess:', tasksToProcess);
262
+ console.log('getTasksToProcess: tasksToProcess count:', tasksToProcess.length);
247
263
  return tasksToProcess;
248
264
  };
249
265
 
@@ -0,0 +1,113 @@
1
+ const js = require('@eslint/js');
2
+ const prettierConfig = require('eslint-config-prettier');
3
+ const importPlugin = require('eslint-plugin-import');
4
+ const prettier = require('eslint-plugin-prettier');
5
+ const promisePlugin = require('eslint-plugin-promise');
6
+ const globals = require('globals');
7
+
8
+ module.exports = [
9
+ // Recommended base configurations
10
+ js.configs.recommended,
11
+ prettierConfig,
12
+
13
+ // Main configuration
14
+ {
15
+ files: ['**/*.js'],
16
+ languageOptions: {
17
+ ecmaVersion: 2021,
18
+ sourceType: 'commonjs',
19
+ globals: {
20
+ ...globals.node,
21
+ ...globals.es2021,
22
+ ...globals.jest,
23
+ },
24
+ },
25
+ plugins: {
26
+ prettier,
27
+ import: importPlugin,
28
+ promise: promisePlugin,
29
+ },
30
+ rules: {
31
+ // Error prevention
32
+ 'no-var': 'error',
33
+ 'no-unused-vars': ['error', { argsIgnorePattern: '^_', varsIgnorePattern: '^_' }],
34
+ 'no-console': ['warn', { allow: ['warn', 'error', 'log', 'info'] }],
35
+ 'no-debugger': 'warn',
36
+ 'no-duplicate-imports': 'error',
37
+ 'no-unused-expressions': ['error', { allowShortCircuit: true, allowTernary: true }],
38
+ 'no-use-before-define': ['error', { functions: false }],
39
+
40
+ // Best practices
41
+ 'prefer-const': 'error',
42
+ 'no-const-assign': 'error',
43
+ 'prefer-arrow-callback': 'error',
44
+ 'arrow-body-style': ['error', 'as-needed'],
45
+ 'no-return-await': 'off',
46
+ 'require-await': 'warn',
47
+
48
+ // Import rules
49
+ 'import/order': [
50
+ 'error',
51
+ {
52
+ groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index'],
53
+ 'newlines-between': 'always',
54
+ alphabetize: { order: 'asc', caseInsensitive: true },
55
+ },
56
+ ],
57
+ 'import/no-unresolved': 'error',
58
+ 'import/no-duplicates': 'error',
59
+ 'import/no-commonjs': 'off',
60
+ 'import/no-dynamic-require': 'off',
61
+
62
+ // Promise rules
63
+ 'promise/always-return': 'off',
64
+ 'promise/no-return-wrap': 'error',
65
+ 'promise/param-names': 'error',
66
+ 'promise/catch-or-return': 'error',
67
+ 'promise/no-native': 'off',
68
+ 'promise/no-callback-in-promise': 'warn',
69
+ 'promise/no-promise-in-callback': 'warn',
70
+ 'promise/no-nesting': 'warn',
71
+
72
+ // Prettier rules
73
+ 'prettier/prettier': [
74
+ 'error',
75
+ {
76
+ singleQuote: true,
77
+ trailingComma: 'es5',
78
+ printWidth: 100,
79
+ tabWidth: 2,
80
+ semi: true,
81
+ bracketSpacing: true,
82
+ arrowParens: 'avoid',
83
+ endOfLine: 'lf',
84
+ },
85
+ ],
86
+ },
87
+ settings: {
88
+ 'import/resolver': {
89
+ node: {
90
+ extensions: ['.js', '.jsx', '.ts', '.tsx'],
91
+ },
92
+ },
93
+ },
94
+ },
95
+
96
+ // Test files override
97
+ {
98
+ files: ['**/*.test.js', '**/*.spec.js'],
99
+ languageOptions: {
100
+ globals: {
101
+ ...globals.jest,
102
+ },
103
+ },
104
+ rules: {
105
+ 'no-console': 'off',
106
+ },
107
+ },
108
+
109
+ // Ignore patterns
110
+ {
111
+ ignores: ['node_modules/**', 'dist/**', 'build/**', 'coverage/**', '*.min.js'],
112
+ },
113
+ ];
package/index.js CHANGED
@@ -1,4 +1,4 @@
1
1
  module.exports = {
2
2
  ...require('./backend'),
3
- ...require('./public')
3
+ ...require('./public'),
4
4
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "psdev-task-manager",
3
- "version": "2.0.5",
3
+ "version": "2.0.6",
4
4
  "description": "Task manager library",
5
5
  "keywords": [
6
6
  "task-manager"
@@ -18,11 +18,27 @@
18
18
  "type": "commonjs",
19
19
  "main": "index.js",
20
20
  "scripts": {
21
- "test": "jest"
21
+ "test": "jest",
22
+ "lint": "eslint .",
23
+ "lint:fix": "eslint . --fix",
24
+ "format": "prettier --write \"**/*.{js,json,md}\"",
25
+ "format:check": "prettier --check \"**/*.{js,json,md}\"",
26
+ "prepare": "husky"
22
27
  },
23
28
  "dependencies": {
24
29
  "@wix/data": "^1.0.273",
25
30
  "@wix/essentials": "^0.1.27",
26
- "psdev-utils": "1.0.2"
31
+ "psdev-utils": "1.1.0"
32
+ },
33
+ "devDependencies": {
34
+ "@eslint/js": "^9.12.0",
35
+ "eslint": "^9.12.0",
36
+ "eslint-config-prettier": "^9.1.0",
37
+ "eslint-plugin-import": "^2.30.0",
38
+ "eslint-plugin-prettier": "^5.2.1",
39
+ "eslint-plugin-promise": "^7.1.0",
40
+ "globals": "^15.10.0",
41
+ "husky": "^9.1.6",
42
+ "prettier": "^3.3.3"
27
43
  }
28
44
  }
package/public/consts.js CHANGED
@@ -26,4 +26,4 @@ const COLLECTIONS_FIELDS = {
26
26
  module.exports = {
27
27
  COLLECTIONS,
28
28
  COLLECTIONS_FIELDS,
29
- };
29
+ };