koatty_schedule 3.0.0 → 3.2.0

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/CHANGELOG.md CHANGED
@@ -2,6 +2,25 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ## [3.2.0](https://github.com/thinkkoa/koatty_schedule/compare/v3.1.0...v3.2.0) (2025-06-22)
6
+
7
+
8
+ ### Features
9
+
10
+ * introduce component-specific metadata keys for scheduled and redlock decorators ([803b350](https://github.com/thinkkoa/koatty_schedule/commit/803b3503489c02ab138b3f9f14cb520dd6c7fec4))
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * 修复IOC容器元数据键格式不匹配问题 ([065d456](https://github.com/thinkkoa/koatty_schedule/commit/065d456fc65004e25eb19838da96bf0a52cb2af1))
16
+
17
+ ## [3.1.0](https://github.com/thinkkoa/koatty_schedule/compare/v3.0.0...v3.1.0) (2025-06-21)
18
+
19
+
20
+ ### Features
21
+
22
+ * update decorator types to support symbol property keys and improve IOC container integration ([a60ef3e](https://github.com/thinkkoa/koatty_schedule/commit/a60ef3e361b245f97ba0d6ee51d42efd437a1252))
23
+
5
24
  ## [3.0.0](https://github.com/thinkkoa/koatty_schedule/compare/v2.1.0...v3.0.0) (2025-06-21)
6
25
 
7
26
 
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * @Author: richen
3
- * @Date: 2025-06-21 14:10:01
3
+ * @Date: 2025-06-22 20:33:52
4
4
  * @License: BSD (3-Clause)
5
5
  * @Copyright (c) - <richenlin(at)gmail.com>
6
6
  * @HomePage: https://koatty.org/
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * @Author: richen
3
- * @Date: 2025-06-21 14:09:54
3
+ * @Date: 2025-06-22 20:33:45
4
4
  * @License: BSD (3-Clause)
5
5
  * @Copyright (c) - <richenlin(at)gmail.com>
6
6
  * @HomePage: https://koatty.org/
@@ -23,6 +23,8 @@ var cron = require('cron');
23
23
  * @License: BSD (3-Clause)
24
24
  * @Copyright (c): <richenlin(at)gmail.com>
25
25
  */
26
+ const COMPONENT_SCHEDULED = 'COMPONENT_SCHEDULED';
27
+ const COMPONENT_REDLOCK = 'COMPONENT_REDLOCK';
26
28
  /**
27
29
  * Decorator types supported by the system
28
30
  */
@@ -184,9 +186,9 @@ function getEffectiveRedLockOptions(methodOptions) {
184
186
  function RedLock(lockName, options) {
185
187
  return (target, propertyKey, descriptor) => {
186
188
  const methodName = propertyKey.toString();
187
- // 验证装饰器使用的类型
188
- const targetObj = target;
189
- const componentType = koatty_container.IOCContainer.getType(targetObj);
189
+ // 验证装饰器使用的类型(从原型对象获取类构造函数)
190
+ const targetClass = target.constructor;
191
+ const componentType = koatty_container.IOCContainer.getType(targetClass);
190
192
  if (componentType !== "SERVICE" && componentType !== "COMPONENT") {
191
193
  throw Error("@RedLock decorator can only be used on SERVICE or COMPONENT classes.");
192
194
  }
@@ -208,12 +210,14 @@ function RedLock(lockName, options) {
208
210
  if (options) {
209
211
  validateRedLockMethodOptions(options);
210
212
  }
213
+ // 保存类到IOC容器
214
+ koatty_container.IOCContainer.saveClass(COMPONENT_REDLOCK, targetClass, targetClass.name);
211
215
  // 保存RedLock元数据到 IOC 容器(lockName已确定)
212
- koatty_container.IOCContainer.attachClassMetadata('COMPONENT', DecoratorType.REDLOCK, {
216
+ koatty_container.IOCContainer.attachClassMetadata(COMPONENT_REDLOCK, DecoratorType.REDLOCK, {
213
217
  method: methodName,
214
218
  name: lockName, // 确定的锁名称,不会为undefined
215
219
  options
216
- }, targetObj, methodName);
220
+ }, target, methodName);
217
221
  };
218
222
  }
219
223
 
@@ -261,26 +265,29 @@ function Scheduled(cron, timezone) {
261
265
  throw Error("Timezone must be a string");
262
266
  }
263
267
  return (target, propertyKey, descriptor) => {
264
- // 验证装饰器使用的类型
265
- const targetObj = target;
266
- const componentType = koatty_container.IOCContainer.getType(targetObj);
268
+ // 验证装饰器使用的类型(从原型对象获取类构造函数)
269
+ const targetClass = target.constructor;
270
+ const componentType = koatty_container.IOCContainer.getType(targetClass);
267
271
  if (componentType !== "SERVICE" && componentType !== "COMPONENT") {
268
272
  throw Error("@Scheduled decorator can only be used on SERVICE or COMPONENT classes.");
269
273
  }
270
274
  // 验证方法名
271
- if (!propertyKey || typeof propertyKey !== 'string') {
275
+ const methodName = propertyKey.toString();
276
+ if (!methodName || typeof methodName !== 'string') {
272
277
  throw Error("Method name is required for @Scheduled decorator");
273
278
  }
274
279
  // 验证方法描述符
275
280
  if (!descriptor || typeof descriptor.value !== 'function') {
276
281
  throw Error("@Scheduled decorator can only be applied to methods");
277
282
  }
278
- // 保存调度元数据到 IOC 容器(timezone如果用户未指定则保存为undefined,在injectSchedule中处理)
279
- koatty_container.IOCContainer.attachClassMetadata('COMPONENT', DecoratorType.SCHEDULED, {
280
- method: propertyKey,
283
+ // 保存类到IOC容器
284
+ koatty_container.IOCContainer.saveClass(COMPONENT_SCHEDULED, targetClass, targetClass.name);
285
+ // 保存调度元数据到 IOC 容器
286
+ koatty_container.IOCContainer.attachClassMetadata(COMPONENT_SCHEDULED, DecoratorType.SCHEDULED, {
287
+ method: methodName,
281
288
  cron,
282
289
  timezone // 保存用户指定的值,可能为undefined
283
- }, targetObj, propertyKey);
290
+ }, target, methodName);
284
291
  };
285
292
  }
286
293
 
@@ -709,12 +716,12 @@ async function initRedLock(options, app) {
709
716
  * @param {RedLockOptions} options - RedLock 配置选项
710
717
  * @param {Koatty} app - Koatty 应用实例
711
718
  */
712
- async function injectRedLock(options, app) {
719
+ async function injectRedLock(_options, _app) {
713
720
  try {
714
721
  koatty_logger.DefaultLogger.Debug('Starting batch RedLock injection...');
715
- const componentList = koatty_container.IOCContainer.listClass("COMPONENT");
722
+ const componentList = koatty_container.IOCContainer.listClass(COMPONENT_REDLOCK);
716
723
  for (const component of componentList) {
717
- const classMetadata = koatty_container.IOCContainer.getClassMetadata('COMPONENT', DecoratorType.REDLOCK, component);
724
+ const classMetadata = koatty_container.IOCContainer.getClassMetadata(COMPONENT_REDLOCK, DecoratorType.REDLOCK, component.target);
718
725
  if (!classMetadata) {
719
726
  continue;
720
727
  }
@@ -727,7 +734,7 @@ async function injectRedLock(options, app) {
727
734
  }
728
735
  // 查找所有RedLock方法的元数据
729
736
  for (const [key, value] of Object.entries(metadata)) {
730
- if (key.startsWith('REDLOCK:')) {
737
+ if (key.startsWith('REDLOCK')) {
731
738
  const redlockData = value;
732
739
  const targetMethod = instance[redlockData.method];
733
740
  if (!koatty_lib.Helper.isFunction(targetMethod)) {
@@ -895,12 +902,12 @@ function redLockerDescriptor(descriptor, name, method, methodOptions) {
895
902
  * @param {RedLockOptions} options - RedLock 配置选项
896
903
  * @param {Koatty} app - Koatty 应用实例
897
904
  */
898
- async function injectSchedule(options, app) {
905
+ async function injectSchedule(_options, _app) {
899
906
  try {
900
907
  koatty_logger.DefaultLogger.Debug('Starting batch schedule injection...');
901
- const componentList = koatty_container.IOCContainer.listClass("COMPONENT");
908
+ const componentList = koatty_container.IOCContainer.listClass(COMPONENT_SCHEDULED);
902
909
  for (const component of componentList) {
903
- const classMetadata = koatty_container.IOCContainer.getClassMetadata('COMPONENT', DecoratorType.SCHEDULED, component);
910
+ const classMetadata = koatty_container.IOCContainer.getClassMetadata(COMPONENT_SCHEDULED, DecoratorType.SCHEDULED, component.target);
904
911
  if (!classMetadata) {
905
912
  continue;
906
913
  }
@@ -913,7 +920,7 @@ async function injectSchedule(options, app) {
913
920
  }
914
921
  // 查找所有调度方法的元数据
915
922
  for (const [key, value] of Object.entries(metadata)) {
916
- if (key.startsWith('SCHEDULED:')) {
923
+ if (key.startsWith('SCHEDULED')) {
917
924
  const scheduleData = value;
918
925
  const targetMethod = instance[scheduleData.method];
919
926
  if (!koatty_lib.Helper.isFunction(targetMethod)) {
@@ -922,7 +929,7 @@ async function injectSchedule(options, app) {
922
929
  }
923
930
  const taskName = `${className}_${scheduleData.method}`;
924
931
  const tz = getEffectiveTimezone(scheduleData.timezone);
925
- const cronJob = new cron.CronJob(scheduleData.cron, () => {
932
+ new cron.CronJob(scheduleData.cron, () => {
926
933
  koatty_logger.DefaultLogger.Debug(`The schedule job ${taskName} started.`);
927
934
  Promise.resolve(targetMethod.call(instance))
928
935
  .then(() => {
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * @Author: richen
3
- * @Date: 2025-06-21 14:09:54
3
+ * @Date: 2025-06-22 20:33:45
4
4
  * @License: BSD (3-Clause)
5
5
  * @Copyright (c) - <richenlin(at)gmail.com>
6
6
  * @HomePage: https://koatty.org/
@@ -21,6 +21,8 @@ import { CronJob } from 'cron';
21
21
  * @License: BSD (3-Clause)
22
22
  * @Copyright (c): <richenlin(at)gmail.com>
23
23
  */
24
+ const COMPONENT_SCHEDULED = 'COMPONENT_SCHEDULED';
25
+ const COMPONENT_REDLOCK = 'COMPONENT_REDLOCK';
24
26
  /**
25
27
  * Decorator types supported by the system
26
28
  */
@@ -182,9 +184,9 @@ function getEffectiveRedLockOptions(methodOptions) {
182
184
  function RedLock(lockName, options) {
183
185
  return (target, propertyKey, descriptor) => {
184
186
  const methodName = propertyKey.toString();
185
- // 验证装饰器使用的类型
186
- const targetObj = target;
187
- const componentType = IOCContainer.getType(targetObj);
187
+ // 验证装饰器使用的类型(从原型对象获取类构造函数)
188
+ const targetClass = target.constructor;
189
+ const componentType = IOCContainer.getType(targetClass);
188
190
  if (componentType !== "SERVICE" && componentType !== "COMPONENT") {
189
191
  throw Error("@RedLock decorator can only be used on SERVICE or COMPONENT classes.");
190
192
  }
@@ -206,12 +208,14 @@ function RedLock(lockName, options) {
206
208
  if (options) {
207
209
  validateRedLockMethodOptions(options);
208
210
  }
211
+ // 保存类到IOC容器
212
+ IOCContainer.saveClass(COMPONENT_REDLOCK, targetClass, targetClass.name);
209
213
  // 保存RedLock元数据到 IOC 容器(lockName已确定)
210
- IOCContainer.attachClassMetadata('COMPONENT', DecoratorType.REDLOCK, {
214
+ IOCContainer.attachClassMetadata(COMPONENT_REDLOCK, DecoratorType.REDLOCK, {
211
215
  method: methodName,
212
216
  name: lockName, // 确定的锁名称,不会为undefined
213
217
  options
214
- }, targetObj, methodName);
218
+ }, target, methodName);
215
219
  };
216
220
  }
217
221
 
@@ -259,26 +263,29 @@ function Scheduled(cron, timezone) {
259
263
  throw Error("Timezone must be a string");
260
264
  }
261
265
  return (target, propertyKey, descriptor) => {
262
- // 验证装饰器使用的类型
263
- const targetObj = target;
264
- const componentType = IOCContainer.getType(targetObj);
266
+ // 验证装饰器使用的类型(从原型对象获取类构造函数)
267
+ const targetClass = target.constructor;
268
+ const componentType = IOCContainer.getType(targetClass);
265
269
  if (componentType !== "SERVICE" && componentType !== "COMPONENT") {
266
270
  throw Error("@Scheduled decorator can only be used on SERVICE or COMPONENT classes.");
267
271
  }
268
272
  // 验证方法名
269
- if (!propertyKey || typeof propertyKey !== 'string') {
273
+ const methodName = propertyKey.toString();
274
+ if (!methodName || typeof methodName !== 'string') {
270
275
  throw Error("Method name is required for @Scheduled decorator");
271
276
  }
272
277
  // 验证方法描述符
273
278
  if (!descriptor || typeof descriptor.value !== 'function') {
274
279
  throw Error("@Scheduled decorator can only be applied to methods");
275
280
  }
276
- // 保存调度元数据到 IOC 容器(timezone如果用户未指定则保存为undefined,在injectSchedule中处理)
277
- IOCContainer.attachClassMetadata('COMPONENT', DecoratorType.SCHEDULED, {
278
- method: propertyKey,
281
+ // 保存类到IOC容器
282
+ IOCContainer.saveClass(COMPONENT_SCHEDULED, targetClass, targetClass.name);
283
+ // 保存调度元数据到 IOC 容器
284
+ IOCContainer.attachClassMetadata(COMPONENT_SCHEDULED, DecoratorType.SCHEDULED, {
285
+ method: methodName,
279
286
  cron,
280
287
  timezone // 保存用户指定的值,可能为undefined
281
- }, targetObj, propertyKey);
288
+ }, target, methodName);
282
289
  };
283
290
  }
284
291
 
@@ -707,12 +714,12 @@ async function initRedLock(options, app) {
707
714
  * @param {RedLockOptions} options - RedLock 配置选项
708
715
  * @param {Koatty} app - Koatty 应用实例
709
716
  */
710
- async function injectRedLock(options, app) {
717
+ async function injectRedLock(_options, _app) {
711
718
  try {
712
719
  DefaultLogger.Debug('Starting batch RedLock injection...');
713
- const componentList = IOCContainer.listClass("COMPONENT");
720
+ const componentList = IOCContainer.listClass(COMPONENT_REDLOCK);
714
721
  for (const component of componentList) {
715
- const classMetadata = IOCContainer.getClassMetadata('COMPONENT', DecoratorType.REDLOCK, component);
722
+ const classMetadata = IOCContainer.getClassMetadata(COMPONENT_REDLOCK, DecoratorType.REDLOCK, component.target);
716
723
  if (!classMetadata) {
717
724
  continue;
718
725
  }
@@ -725,7 +732,7 @@ async function injectRedLock(options, app) {
725
732
  }
726
733
  // 查找所有RedLock方法的元数据
727
734
  for (const [key, value] of Object.entries(metadata)) {
728
- if (key.startsWith('REDLOCK:')) {
735
+ if (key.startsWith('REDLOCK')) {
729
736
  const redlockData = value;
730
737
  const targetMethod = instance[redlockData.method];
731
738
  if (!Helper.isFunction(targetMethod)) {
@@ -893,12 +900,12 @@ function redLockerDescriptor(descriptor, name, method, methodOptions) {
893
900
  * @param {RedLockOptions} options - RedLock 配置选项
894
901
  * @param {Koatty} app - Koatty 应用实例
895
902
  */
896
- async function injectSchedule(options, app) {
903
+ async function injectSchedule(_options, _app) {
897
904
  try {
898
905
  DefaultLogger.Debug('Starting batch schedule injection...');
899
- const componentList = IOCContainer.listClass("COMPONENT");
906
+ const componentList = IOCContainer.listClass(COMPONENT_SCHEDULED);
900
907
  for (const component of componentList) {
901
- const classMetadata = IOCContainer.getClassMetadata('COMPONENT', DecoratorType.SCHEDULED, component);
908
+ const classMetadata = IOCContainer.getClassMetadata(COMPONENT_SCHEDULED, DecoratorType.SCHEDULED, component.target);
902
909
  if (!classMetadata) {
903
910
  continue;
904
911
  }
@@ -911,7 +918,7 @@ async function injectSchedule(options, app) {
911
918
  }
912
919
  // 查找所有调度方法的元数据
913
920
  for (const [key, value] of Object.entries(metadata)) {
914
- if (key.startsWith('SCHEDULED:')) {
921
+ if (key.startsWith('SCHEDULED')) {
915
922
  const scheduleData = value;
916
923
  const targetMethod = instance[scheduleData.method];
917
924
  if (!Helper.isFunction(targetMethod)) {
@@ -920,7 +927,7 @@ async function injectSchedule(options, app) {
920
927
  }
921
928
  const taskName = `${className}_${scheduleData.method}`;
922
929
  const tz = getEffectiveTimezone(scheduleData.timezone);
923
- const cronJob = new CronJob(scheduleData.cron, () => {
930
+ new CronJob(scheduleData.cron, () => {
924
931
  DefaultLogger.Debug(`The schedule job ${taskName} started.`);
925
932
  Promise.resolve(targetMethod.call(instance))
926
933
  .then(() => {
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "koatty_schedule",
3
- "version": "3.0.0",
3
+ "version": "3.2.0",
4
4
  "description": "Schedule for koatty.",
5
5
  "scripts": {
6
6
  "build": "npm run build:js && npm run build:dts && npm run build:doc && npm run build:cp",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "koatty_schedule",
3
- "version": "3.0.0",
3
+ "version": "3.2.0",
4
4
  "description": "Schedule for koatty.",
5
5
  "scripts": {
6
6
  "build": "npm run build:js && npm run build:dts && npm run build:doc && npm run build:cp",