psdev-task-manager 1.4.7 → 1.7.1

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.
@@ -1,21 +1,30 @@
1
1
  name: Update Sites After Release Main
2
2
 
3
3
  on:
4
+ push:
5
+ branches:
6
+ - main
4
7
  workflow_dispatch:
5
-
8
+
6
9
  permissions:
7
- contents: write
8
- packages: write
9
-
10
+ contents: write
11
+ packages: write
12
+
10
13
  jobs:
11
14
  update-sites:
12
- uses: psdevteamenterprise/ci-workflows/.github/workflows/publish-and-notify.yml@main
15
+ uses: psdevteamenterprise/ci-workflows/.github/workflows/update-and-notify.yml@main
13
16
  with:
14
- sites_to_update: "['psdevteamenterprise/tests-site']"
15
-
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
+ {repo: 'psdevteamenterprise/hisense_mexico', secret: 'WIX_HM_API_KEY'},
22
+ ]"
16
23
  secrets:
17
24
  GH_TOKEN: ${{ secrets.MY_GITHUB_TOKEN }}
18
25
  NPM_TOKEN: ${{ secrets.NPM_TOKEN_PUBLISH }}
19
26
  GH_APP_ID: ${{ secrets.GH_APP_ID }}
20
27
  GH_APP_PRIVATE_KEY: ${{ secrets.GH_APP_PRIVATE_KEY }}
21
- WIX_CLI_API_KEY: ${{ secrets.PS_WIX_ACCOUNT_TOKEN }}
28
+ WIX_SR_API_KEY: ${{secrets.WIX_SR_API_KEY}}
29
+ WIX_PS_API_KEY: ${{secrets.WIX_PS_API_KEY}}
30
+ WIX_HM_API_KEY: ${{secrets.WIX_HM_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,33 @@ 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
+
79
+ //Only throw error if task is permanently failed, otherwise we have retry mechanism
80
+ throw new Error("task failed after all retries: " + errMsg);
81
+ }
77
82
  }
78
83
  },
79
84
  console
80
85
  );
86
+ const processTask = (...args) => {
87
+ const requestName = `processTask_${args[0].name}`; //To get success rate analysis per task
88
+ return withSuccessRateLogs(requestName, () => processTaskWithDuration(...args));
89
+ };
81
90
  /**
82
91
  * @description Processing tasks based on how many the cron job tick can handle and running them sequentially to be as safe as possible
83
92
  * */
84
93
  const processTasksBasedOnVeloLimit = async (scheduledTasks, tasksConfig) => {
85
94
  console.log(
86
- `processTasksBasedOnVeloLimit: ${JSON.stringify(scheduledTasks)} ${JSON.stringify(tasksConfig)}`
95
+ `processTasksBasedOnVeloLimit: scheduledTasks count: ${scheduledTasks.length} tasksConfig: ${JSON.stringify(tasksConfig)}`
87
96
  );
88
97
  const toProcessTasks = getTasksToProcess({
89
98
  scheduledTasks,
90
99
  tasksConfig,
91
100
  maxDuration: CRON_JOB_MAX_DURATION_SEC,
92
101
  });
93
- console.log(`processTasksBasedOnVeloLimit: toProcessTasks: ${JSON.stringify(toProcessTasks)}`);
102
+ console.log(`processTasksBasedOnVeloLimit: toProcessTasks count: ${toProcessTasks.length}`);
94
103
  console.log(
95
104
  `[processTasksBasedOnVeloLimit] started processing: ${toProcessTasks.length} tasks`
96
105
  );
@@ -113,8 +122,7 @@ function taskManager() {
113
122
  const runScheduledTasks = async tasksConfig => {
114
123
  try {
115
124
  const scheduledTasks = await getScheduledTasks();
116
- console.log(`runScheduledTasks: scheduledTasks: ${JSON.stringify(scheduledTasks)}`);
117
- console.log(`runScheduledTasks: tasksConfig: ${JSON.stringify(tasksConfig)}`);
125
+ console.log(`runScheduledTasks: scheduledTasks count: ${scheduledTasks.length}`);
118
126
  if (scheduledTasks.length) {
119
127
  await processTasksBasedOnVeloLimit(scheduledTasks, tasksConfig);
120
128
  } else {
@@ -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
  ];
@@ -168,19 +168,29 @@ const isParentTask = (task, taskConfig) => {
168
168
  return true;
169
169
  };
170
170
  const filterScheduledTasksByStatus = (tasks, tasksConfig) => {
171
- console.log(
172
- `filterScheduledTasksByStatus: ${JSON.stringify(tasks)} ${JSON.stringify(tasksConfig)}`
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]);
171
+
172
+ const shouldIncludeTask = (task, taskConfig) => {
173
+ console.log(`filterScheduledTasksByStatus: task: ${JSON.stringify(task)}`);
174
+ console.log(`filterScheduledTasksByStatus: taskConfig: ${JSON.stringify(taskConfig)}`);
175
+ const { status } = task;
176
+ if (status === TASK_STATUS.IN_PROGRESS) {
177
+ //Only include parent tasks that are in progress, to continue running next children
178
+ return isParentTask(task, taskConfig);
180
179
  }
180
+ //TODO: need to rethink of this as some parent tasks we use only to schedule children,
181
+ // if (status === TASK_STATUS.FAILED) {
182
+ // // Exclude if it's a parent task, if parent task failed, we don't retry it anymore
183
+ // return !isParentTask(task, taskConfig);
184
+ // }
185
+ // // Include if status is PENDING
186
+ // return status === TASK_STATUS.PENDING;
181
187
  return [TASK_STATUS.PENDING, TASK_STATUS.FAILED].includes(task.status);
188
+ };
189
+ const filtered = tasks.filter(task => {
190
+ const taskConfig = tasksConfig[task.name];
191
+ return shouldIncludeTask(task, taskConfig);
182
192
  });
183
- console.log(`filterScheduledTasksByStatus: filtered: ${JSON.stringify(filtered)}`);
193
+ console.log(`filterScheduledTasksByStatus: filtered count: ${filtered.length}`);
184
194
  return filtered;
185
195
  };
186
196
  const getScheduledTasks = async () => {
@@ -221,16 +231,18 @@ const getTaskScheduledChildren = async parentTaskId => {
221
231
  };
222
232
 
223
233
  const getTasksToProcess = ({ scheduledTasks, tasksConfig, maxDuration }) => {
224
- console.log('getTasksToProcess:', { scheduledTasks, tasksConfig, maxDuration });
234
+ console.log('getTasksToProcess:', {
235
+ scheduledTasksCount: scheduledTasks.length,
236
+ tasksConfig,
237
+ maxDuration,
238
+ });
225
239
  const tasksToProcess = [];
226
240
  let totalDuration = 0;
227
- console.log(`tasksConfig is : ${JSON.stringify(tasksConfig)}`);
228
241
  const filteredScheduledTasks = filterScheduledTasksByStatus(scheduledTasks, tasksConfig);
229
- console.log(`filteredScheduledTasks is : ${JSON.stringify(filteredScheduledTasks)}`);
242
+ console.log(`filteredScheduledTasks count : ${filteredScheduledTasks.length}`);
230
243
  for (const task of filteredScheduledTasks) {
231
244
  console.log(`task is : ${JSON.stringify(task)}`);
232
245
  const taskConfig = getTaskConfig(task.name, tasksConfig);
233
- console.log(`taskConfig is : ${JSON.stringify(taskConfig)}`);
234
246
  const estimated = taskConfig?.estimatedDurationSec;
235
247
  if (!estimated) {
236
248
  const errMsg = `[getTasksToProcess] estimatedDurationSec is not defined for task ${task.name}`;
@@ -243,7 +255,7 @@ const getTasksToProcess = ({ scheduledTasks, tasksConfig, maxDuration }) => {
243
255
  totalDuration += buffered;
244
256
  tasksToProcess.push(task);
245
257
  }
246
- console.log('getTasksToProcess: tasksToProcess:', tasksToProcess);
258
+ console.log('getTasksToProcess: tasksToProcess count:', tasksToProcess.length);
247
259
  return tasksToProcess;
248
260
  };
249
261
 
@@ -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": "1.4.7",
3
+ "version": "1.7.1",
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
+ };