hyper-scheduler 1.0.1 → 1.1.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/README.md +17 -0
- package/dist/devtools-Bxtz0rO_.cjs +1 -0
- package/dist/{devtools-4xVHTaUz.js → devtools-ByJU-Gv1.js} +378 -34
- package/dist/index.cjs +1 -1
- package/dist/index.js +91 -38
- package/dist/index.umd.cjs +1 -1
- package/docs/.vitepress/cache/deps/_metadata.json +31 -0
- package/docs/.vitepress/cache/deps/chunk-EKBJ2FPM.js +12798 -0
- package/docs/.vitepress/cache/deps/chunk-EKBJ2FPM.js.map +7 -0
- package/docs/.vitepress/cache/deps/package.json +3 -0
- package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js +4505 -0
- package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map +7 -0
- package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js +9731 -0
- package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js.map +7 -0
- package/docs/.vitepress/cache/deps/vue.js +347 -0
- package/docs/.vitepress/cache/deps/vue.js.map +7 -0
- package/docs/.vitepress/config.ts +56 -0
- package/docs/.vitepress/theme/components/DemoFrame.vue +111 -0
- package/docs/.vitepress/theme/custom.css +6 -0
- package/docs/.vitepress/theme/index.ts +10 -0
- package/docs/README.md +120 -0
- package/docs/api/devtools.md +245 -0
- package/docs/api/index.md +178 -0
- package/docs/api/scheduler.md +342 -0
- package/docs/api/task.md +439 -0
- package/docs/api/types.md +365 -0
- package/docs/examples/index.md +342 -0
- package/docs/guide/best-practices.md +436 -0
- package/docs/guide/core-concepts.md +363 -0
- package/docs/guide/getting-started.md +176 -0
- package/docs/index.md +33 -0
- package/docs/public/logo.svg +54 -0
- package/package.json +9 -6
- package/dist/devtools-DdQ1I25H.cjs +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var t=Object.defineProperty,e=(e,s,i)=>((e,s,i)=>s in e?t(e,s,{enumerable:!0,configurable:!0,writable:!0,value:i}):e[s]=i)(e,"symbol"!=typeof s?s+"":s,i);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s={IDLE:"idle",RUNNING:"running",STOPPED:"stopped",ERROR:"error"},i={TASK_REGISTERED:"task_registered",TASK_STARTED:"task_started",TASK_COMPLETED:"task_completed",TASK_FAILED:"task_failed",TASK_STOPPED:"task_stopped",TASK_REMOVED:"task_removed",TASK_UPDATED:"task_updated",SCHEDULER_STARTED:"scheduler_started",SCHEDULER_STOPPED:"scheduler_stopped"};class r{constructor(){e(this,"tasks"),this.tasks=new Map}addTask(t){if(this.tasks.has(t.id))throw new Error(`Task with ID "${t.id}" already exists.`);this.tasks.set(t.id,t)}getTask(t){return this.tasks.get(t)}deleteTask(t){return this.tasks.delete(t)}getAllTasks(){return Array.from(this.tasks.values())}clear(){this.tasks.clear()}}function n(t,e,s){const i=new Set;if("*"===t){for(let t=e;t<=s;t++)i.add(t);return Array.from(i).sort((t,e)=>t-e)}const r=t.split(",");for(const n of r)if(n.includes("/")){const[t,r]=n.split("/"),o=parseInt(r,10);if("*"===t)for(let n=e;n<=s;n+=o)i.add(n);else if(t.includes("-")){const[r,n]=t.split("-").map(Number);if(r<e||n>s)throw new Error(`Value out of range: ${r}-${n} (expected ${e}-${s})`);for(let t=r;t<=n;t+=o)i.add(t)}else{const r=parseInt(t,10);if(r<e||r>s)throw new Error(`Value out of range: ${r} (expected ${e}-${s})`);for(let t=r;t<=s;t+=o)i.add(t)}}else if(n.includes("-")){const[t,r]=n.split("-").map(Number);if(t<e||r>s)throw new Error(`Value out of range: ${t}-${r} (expected ${e}-${s})`);for(let e=t;e<=r;e++)i.add(e)}else{const t=parseInt(n,10);if(t<e||t>s)throw new Error(`Value out of range: ${t} (expected ${e}-${s})`);i.add(t)}return Array.from(i).sort((t,e)=>t-e)}function o(t){const e=t.trim().split(/\s+/);let s,i,r,o,a,l;if(5===e.length)s=[0],[i,r,o,a,l]=[n(e[0],0,59),n(e[1],0,23),n(e[2],1,31),n(e[3],1,12),n(e[4],0,6)];else{if(6!==e.length)throw new Error(`Invalid cron expression: expected 5 or 6 fields, got ${e.length}`);[s,i,r,o,a,l]=[n(e[0],0,59),n(e[1],0,59),n(e[2],0,23),n(e[3],1,31),n(e[4],1,12),n(e[5],0,6)]}return{second:s,minute:i,hour:r,dayOfMonth:o,month:a,dayOfWeek:l}}function a(t,e){const s=t.getSeconds(),i=t.getMinutes(),r=t.getHours(),n=t.getDate(),o=t.getMonth()+1,a=t.getDay();return e.second.includes(s)&&e.minute.includes(i)&&e.hour.includes(r)&&e.month.includes(o)&&(e.dayOfMonth.includes(n)||e.dayOfWeek.includes(a))}function l(t){const e=t.match(/^(\d+)(s|m|h|d)$/);if(e){const t=parseInt(e[1],10);let s=1e3;switch(e[2]){case"s":s=1e3;break;case"m":s=6e4;break;case"h":s=36e5;break;case"d":s=864e5}return{type:"interval",value:t*s}}try{return function(t){try{o(t)}catch(e){throw new Error(`Invalid cron expression: ${t}`)}}(t),{type:"cron",value:t}}catch(s){throw new Error(`无效的调度格式: "${t}". 必须是有效的 Cron 表达式或间隔字符串 (例如 "10s")。`)}}function c(t,e){let s;if(s="string"==typeof t?l(t):t,"interval"===s.type){const t=s.value,i=(null==e?void 0:e.lastRun)||Date.now();return new Date(i+t)}{const t=s.value;try{return function(t){const e=o(t);let s=new Date((new Date).getTime()+1e3);s.setMilliseconds(0);let i=0;for(;i<126144e3;){if(a(s,e))return s;const t=s.getSeconds(),r=s.getMinutes(),n=s.getHours();if(!e.second.includes(t)){const n=e.second.find(e=>e>t)??e.second[0];n>t?s.setSeconds(n):s.setMinutes(r+1,n),s.setMilliseconds(0),i++;continue}if(!e.minute.includes(r)){const t=e.minute.find(t=>t>r)??e.minute[0];t>r?s.setMinutes(t,e.second[0]):s.setHours(n+1,t,e.second[0]),s.setMilliseconds(0),i++;continue}if(!e.hour.includes(n)){const t=e.hour.find(t=>t>n)??e.hour[0];t>n||s.setDate(s.getDate()+1),s.setHours(t,e.minute[0],e.second[0]),s.setMilliseconds(0),i++;continue}s=new Date(s.getTime()+1e3),i++}throw new Error(`Could not find next run time for cron expression: ${t}`)}(t,null==e||e.timezone)}catch(i){throw new Error(`无法计算下一次 Cron 运行时间: ${t}`)}}}class u{static getDelay(t,e){if(!e)return-1;const{maxAttempts:s,initialDelay:i,factor:r=2}=e;return t>=s?-1:i*Math.pow(r,t)}}let d=class{constructor(t,s={},i){e(this,"registry"),e(this,"config"),e(this,"defaultTimerStrategy"),e(this,"timerStrategyFactory"),e(this,"taskTimerStrategies"),e(this,"running"),e(this,"timers"),e(this,"listeners"),e(this,"eventListeners"),this.registry=new r,this.defaultTimerStrategy=t,this.timerStrategyFactory=i,this.taskTimerStrategies=new Map,this.config={debug:!1,maxHistory:50,...s},this.running=!1,this.timers=new Map,this.listeners=[],this.eventListeners=new Map,this.config.plugins&&Array.isArray(this.config.plugins)&&this.config.plugins.forEach(t=>{try{this.log(`Initializing plugin: ${t.name}`),t.init(this)}catch(e){console.warn(`[HyperScheduler] Failed to initialize plugin ${t.name}:`,e)}})}subscribe(t){return this.listeners.push(t),()=>{this.listeners=this.listeners.filter(e=>e!==t)}}on(t,e){return this.eventListeners.has(t)||this.eventListeners.set(t,new Set),this.eventListeners.get(t).add(e),()=>{var s;null==(s=this.eventListeners.get(t))||s.delete(e)}}emit(t,e){const s=this.eventListeners.get(t);s&&s.forEach(t=>t(e))}getTimerStrategy(t){var e;const s=null==(e=t.options)?void 0:e.driver,i=this.config.driver,r=s||i;if(!r||!this.timerStrategyFactory)return this.defaultTimerStrategy;const n=`${t.id}_${r}`;if(this.taskTimerStrategies.has(n))return this.taskTimerStrategies.get(n);const o=this.timerStrategyFactory(r);return this.taskTimerStrategies.set(n,o),o}notify(){if(this.listeners.length>0){const t=this.registry.getAllTasks();this.listeners.forEach(e=>e(t))}}createTask(t){!function(t){if(!t||"string"!=typeof t||""===t.trim())throw new Error("Task ID must be a non-empty string.")}(t.id),l(t.schedule);const e={...t,tags:t.tags||[],status:s.STOPPED,history:[],executionCount:0};this.registry.addTask(e),this.log(`Task created: ${e.id}`),this.emit(i.TASK_REGISTERED,{taskId:e.id,task:e}),this.notify(),this.running&&(e.status=s.IDLE,this.scheduleTask(e))}deleteTask(t){this.stopTask(t);const e=this.registry.deleteTask(t);return e&&(this.log(`Task deleted: ${t}`),this.emit(i.TASK_REMOVED,{taskId:t}),this.notify()),e}startTask(t){const e=this.registry.getTask(t);if(!e)throw new Error(`Task not found: ${t}`);if(e.status===s.RUNNING)return;const r=this.timers.get(t);r&&(this.getTimerStrategy(e).cancel(r),this.timers.delete(t)),e.status=s.IDLE,this.log(`Starting task: ${t}`),this.emit(i.TASK_STARTED,{taskId:t,task:e}),this.notify(),this.scheduleTaskForce(e)}scheduleTaskForce(t){var e;try{const s=c(t.schedule,{timezone:(null==(e=t.options)?void 0:e.timezone)||this.config.timezone,lastRun:t.lastRun});t.nextRun=s.getTime();const i=Date.now(),r=Math.max(0,s.getTime()-i);this.log(`Scheduling task ${t.id} for ${s.toISOString()} (in ${r}ms)`);const n=this.getTimerStrategy(t).schedule(()=>{this.executeTaskIndividual(t)},r);this.timers.set(t.id,n)}catch(i){this.log(`Error scheduling task ${t.id}: ${i}`),t.status=s.ERROR,this.notify()}}async executeTaskIndividual(t,e=0){var r,n;if(this.timers.delete(t.id),t.status===s.STOPPED)return;t.status=s.RUNNING,t.lastRun=Date.now(),t.executionCount=(t.executionCount||0)+1;const o=Date.now();this.log(`Executing task: ${t.id} (Attempt ${e})`),this.emit(i.TASK_STARTED,{taskId:t.id,task:t}),this.notify();try{await t.handler();const e=Date.now()-o;this.recordHistory(t,{timestamp:o,duration:e,success:!0}),t.status=s.IDLE,this.log(`Task execution success: ${t.id}`),this.emit(i.TASK_COMPLETED,{taskId:t.id,task:t,duration:e}),this.notify(),this.scheduleTaskForce(t)}catch(a){const c=Date.now()-o;if(this.recordHistory(t,{timestamp:o,duration:c,success:!1,error:a.message}),this.log(`Task execution failed: ${t.id} - ${a.message}`),this.emit(i.TASK_FAILED,{taskId:t.id,task:t,error:a.message,duration:c}),null==(r=t.options)?void 0:r.onError)try{t.options.onError(a,t.id)}catch(l){this.log(`onError callback failed: ${l}`)}const d=u.getDelay(e,null==(n=t.options)?void 0:n.retry);if(d>=0){this.log(`Retrying task ${t.id} in ${d}ms (Attempt ${e+1})`);const i=this.getTimerStrategy(t).schedule(()=>{this.executeTaskIndividual(t,e+1)},d);this.timers.set(t.id,i),t.status=s.ERROR,this.notify()}else t.status=s.ERROR,this.notify(),this.scheduleTaskForce(t)}}stopTask(t){const e=this.registry.getTask(t),r=this.timers.get(t);r&&e?(this.getTimerStrategy(e).cancel(r),this.timers.delete(t)):r&&(this.defaultTimerStrategy.cancel(r),this.timers.delete(t)),e&&(e.status=s.STOPPED,this.log(`Task stopped: ${t}`),this.emit(i.TASK_STOPPED,{taskId:t,task:e}),this.notify())}getTask(t){return this.registry.getTask(t)}getAllTasks(){return this.registry.getAllTasks()}isRunning(){return this.running}getTaskDriver(t){var e;const s=this.registry.getTask(t);return s?(null==(e=s.options)?void 0:e.driver)||this.config.driver||"worker":this.config.driver||"worker"}getGlobalDriver(){return this.config.driver||"worker"}async triggerTask(t){const e=this.getTask(t);if(!e)return;if(e.status===s.RUNNING)return;const r=e.status;e.status=s.RUNNING,e.lastRun=Date.now(),e.executionCount=(e.executionCount||0)+1;const n=Date.now();this.log(`Triggering task: ${e.id}`),this.emit(i.TASK_STARTED,{taskId:e.id,task:e}),this.notify();try{await e.handler();const t=Date.now()-n;this.recordHistory(e,{timestamp:n,duration:t,success:!0}),e.status=r,this.log(`Task trigger success: ${e.id}`),this.emit(i.TASK_COMPLETED,{taskId:e.id,task:e,duration:t}),this.notify()}catch(o){const t=Date.now()-n;this.recordHistory(e,{timestamp:n,duration:t,success:!1,error:o.message}),this.log(`Task trigger failed: ${e.id} - ${o.message}`),this.emit(i.TASK_FAILED,{taskId:e.id,task:e,error:o.message,duration:t}),e.status=r,this.notify()}}start(){this.running||(this.running=!0,this.log("Scheduler started"),this.emit(i.SCHEDULER_STARTED,{running:!0}),this.registry.getAllTasks().forEach(t=>{t.status===s.STOPPED&&(t.status=s.IDLE,this.emit(i.TASK_UPDATED,{taskId:t.id,task:t})),t.status!==s.RUNNING&&this.scheduleTask(t)}),this.notify())}stop(){this.running=!1,this.log("Scheduler stopped"),this.emit(i.SCHEDULER_STOPPED,{running:!1}),this.timers.forEach((t,e)=>{const s=this.registry.getTask(e);s?this.getTimerStrategy(s).cancel(t):this.defaultTimerStrategy.cancel(t)}),this.timers.clear(),this.registry.getAllTasks().forEach(t=>{t.status!==s.STOPPED&&(t.status=s.STOPPED,this.emit(i.TASK_UPDATED,{taskId:t.id,task:t}))}),this.notify()}scheduleTask(t){var e;if(this.running||t.status===s.RUNNING)try{const s=c(t.schedule,{timezone:(null==(e=t.options)?void 0:e.timezone)||this.config.timezone,lastRun:t.lastRun});t.nextRun=s.getTime();const i=Date.now(),r=Math.max(0,s.getTime()-i);this.log(`Scheduling task ${t.id} for ${s.toISOString()} (in ${r}ms)`);const n=this.getTimerStrategy(t).schedule(()=>{this.executeTask(t)},r);this.timers.set(t.id,n)}catch(i){this.log(`Error scheduling task ${t.id}: ${i}`),t.status=s.ERROR}}async executeTask(t,e=0,r=!1){var n,o;if(this.timers.delete(t.id),!(r||this.running&&t.status!==s.STOPPED))return;t.status=s.RUNNING,t.lastRun=Date.now(),t.executionCount=(t.executionCount||0)+1;const a=Date.now();this.log(`Executing task: ${t.id} (Attempt ${e})`),this.emit(i.TASK_STARTED,{taskId:t.id,task:t}),this.notify();try{await t.handler();const e=Date.now()-a;this.recordHistory(t,{timestamp:a,duration:e,success:!0}),t.status=s.IDLE,this.log(`Task execution success: ${t.id}`),this.emit(i.TASK_COMPLETED,{taskId:t.id,task:t,duration:e}),this.notify(),this.scheduleTask(t)}catch(l){const r=Date.now()-a;if(this.recordHistory(t,{timestamp:a,duration:r,success:!1,error:l.message}),this.log(`Task execution failed: ${t.id} - ${l.message}`),this.emit(i.TASK_FAILED,{taskId:t.id,task:t,error:l.message,duration:r}),null==(n=t.options)?void 0:n.onError)try{t.options.onError(l,t.id)}catch(c){this.log(`onError callback failed: ${c}`)}const d=u.getDelay(e,null==(o=t.options)?void 0:o.retry);if(d>=0){this.log(`Retrying task ${t.id} in ${d}ms (Attempt ${e+1})`);const i=this.getTimerStrategy(t).schedule(()=>{this.executeTask(t,e+1)},d);this.timers.set(t.id,i),t.status=s.ERROR,this.notify()}else t.status=s.ERROR,this.notify(),this.scheduleTask(t)}}recordHistory(t,e){t.history.unshift(e),this.config.maxHistory&&t.history.length>this.config.maxHistory&&t.history.pop()}log(t){this.config.debug&&console.log(`[HyperScheduler] ${t}`)}};class h{schedule(t,e){return setTimeout(t,e)}cancel(t){clearTimeout(t)}}const g="IWZ1bmN0aW9uKCl7InVzZSBzdHJpY3QiO2NvbnN0IGU9bmV3IE1hcDtzZWxmLm9ubWVzc2FnZT1zPT57Y29uc3R7aWQ6dCxkZWxheTpjLHR5cGU6bH09cy5kYXRhO2lmKCJzY2hlZHVsZSI9PT1sKXtjb25zdCBzPXNlbGYuc2V0VGltZW91dCgoKT0+e3NlbGYucG9zdE1lc3NhZ2Uoe2lkOnQsdHlwZToidGljayJ9KSxlLmRlbGV0ZSh0KX0sYyk7ZS5zZXQodCxzKX1lbHNlIGlmKCJjYW5jZWwiPT09bCl7Y29uc3Qgcz1lLmdldCh0KTt2b2lkIDAhPT1zJiYoc2VsZi5jbGVhclRpbWVvdXQocyksZS5kZWxldGUodCkpfX19KCk7Cg==",m="undefined"!=typeof self&&self.Blob&&new Blob([(k=g,Uint8Array.from(atob(k),t=>t.charCodeAt(0)))],{type:"text/javascript;charset=utf-8"});var k;function T(t){let e;try{if(e=m&&(self.URL||self.webkitURL).createObjectURL(m),!e)throw"";const s=new Worker(e,{name:null==t?void 0:t.name});return s.addEventListener("error",()=>{(self.URL||self.webkitURL).revokeObjectURL(e)}),s}catch(s){return new Worker("data:text/javascript;base64,"+g,{name:null==t?void 0:t.name})}finally{e&&(self.URL||self.webkitURL).revokeObjectURL(e)}}class f{constructor(){e(this,"worker"),e(this,"callbacks"),e(this,"nextId"),this.worker=void 0!==T?new T:{postMessage:()=>{},onmessage:null,terminate:()=>{},addEventListener:()=>{},removeEventListener:()=>{},dispatchEvent:()=>!1},this.callbacks=new Map,this.nextId=1,this.worker.onmessage=t=>{const{id:e,type:s}=t.data;if("tick"===s){const t=this.callbacks.get(e);t&&(t(),this.callbacks.delete(e))}}}schedule(t,e){const s=this.nextId++;return this.callbacks.set(s,t),this.worker.postMessage({id:s,delay:e,type:"schedule"}),s}cancel(t){this.worker.postMessage({id:t,type:"cancel"}),this.callbacks.delete(t)}}class y{schedule(t,e){return window.setTimeout(t,e)}cancel(t){window.clearTimeout(t)}}const p="undefined"!=typeof window&&void 0!==window.document;let E=null,S=null;exports.CoreScheduler=d,exports.DevTools=class{constructor(t={}){e(this,"name","DevTools"),e(this,"options"),this.options=t}init(t){"undefined"!=typeof window&&void 0!==window.document&&this.mount(t)}async mount(t){try{await Promise.resolve().then(()=>require("./devtools-DdQ1I25H.cjs")),await customElements.whenDefined("hs-devtools"),this.setupElement(t)}catch(e){console.error("[DevTools] Failed to mount:",e)}}setupElement(t){try{let e=document.querySelector("hs-devtools");e&&e.remove(),e=document.createElement("hs-devtools");const i=this.options;console.log("[DevTools Plugin] options:",JSON.stringify(i)),i.theme&&e.setAttribute("theme",i.theme),i.dockPosition&&e.setAttribute("dock",i.dockPosition),i.language&&e.setAttribute("language",i.language),i.defaultZoom&&e.setAttribute("default-zoom",i.defaultZoom.toString()),i.trigger&&(i.trigger.backgroundColor&&e.setAttribute("trigger-bg",i.trigger.backgroundColor),i.trigger.textColor&&e.setAttribute("trigger-color",i.trigger.textColor),i.trigger.position&&e.setAttribute("trigger-position",i.trigger.position)),console.log("[DevTools Plugin] attributes set:",e.getAttribute("dock"),e.getAttribute("trigger-position")),document.body.appendChild(e),"function"==typeof e.setScheduler?e.setScheduler({getTasks:()=>t.getAllTasks().map(e=>({id:e.id,status:e.status,lastRun:e.lastRun||null,nextRun:e.nextRun||null,executionCount:e.executionCount||0,schedule:e.schedule,tags:e.tags||[],error:e.status===s.ERROR?"Execution failed":null,driver:t.getTaskDriver(e.id)})),on:(e,s)=>t.on(e,s),isRunning:()=>t.isRunning(),trigger:e=>t.triggerTask(e),pause:e=>t.stopTask(e),resume:e=>t.startTask(e),remove:e=>t.deleteTask(e)}):console.warn("[DevTools] hs-devtools element does not have setScheduler method.")}catch(e){console.error("[DevTools] Failed to setup element:",e)}}},exports.Scheduler=class extends d{constructor(t){super(function(t){if(p)return"main"===((null==t?void 0:t.driver)||"worker")?(S||(S=new y),S):(E||(E=new f),E);return new h}(t),t,function(){if(p)return t=>"main"===t?(S||(S=new y),S):(E||(E=new f),E)}())}},exports.SchedulerEvents=i,exports.TaskStatus=s;
|
|
1
|
+
"use strict";var t=Object.defineProperty,e=(e,s,i)=>((e,s,i)=>s in e?t(e,s,{enumerable:!0,configurable:!0,writable:!0,value:i}):e[s]=i)(e,"symbol"!=typeof s?s+"":s,i);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s={IDLE:"idle",RUNNING:"running",STOPPED:"stopped",ERROR:"error"},i={TASK_REGISTERED:"task_registered",TASK_STARTED:"task_started",TASK_COMPLETED:"task_completed",TASK_FAILED:"task_failed",TASK_STOPPED:"task_stopped",TASK_REMOVED:"task_removed",TASK_UPDATED:"task_updated",SCHEDULER_STARTED:"scheduler_started",SCHEDULER_STOPPED:"scheduler_stopped"};class r{constructor(){e(this,"tasks"),e(this,"namespaceIndex"),this.tasks=new Map,this.namespaceIndex=new Map}addTask(t){var e,s;if(this.tasks.has(t.id))throw new Error(`Task with ID "${t.id}" already exists.`);this.tasks.set(t.id,t);const i=(null==(e=t.options)?void 0:e.namespace)||"default";this.namespaceIndex.has(i)||this.namespaceIndex.set(i,new Set),null==(s=this.namespaceIndex.get(i))||s.add(t.id)}getTask(t){return this.tasks.get(t)}deleteTask(t){var e,s,i;const r=this.tasks.get(t);if(!r)return!1;const n=(null==(e=r.options)?void 0:e.namespace)||"default";return null==(s=this.namespaceIndex.get(n))||s.delete(t),0===(null==(i=this.namespaceIndex.get(n))?void 0:i.size)&&this.namespaceIndex.delete(n),this.tasks.delete(t)}getAllTasks(){return Array.from(this.tasks.values())}getTasksByNamespace(t){const e=this.namespaceIndex.get(t);return e?Array.from(e).map(t=>this.tasks.get(t)).filter(Boolean):[]}clear(){this.tasks.clear(),this.namespaceIndex.clear()}}function n(t,e,s){const i=new Set;if("*"===t){for(let t=e;t<=s;t++)i.add(t);return Array.from(i).sort((t,e)=>t-e)}const r=t.split(",");for(const n of r)if(n.includes("/")){const[t,r]=n.split("/"),o=parseInt(r,10);if("*"===t)for(let n=e;n<=s;n+=o)i.add(n);else if(t.includes("-")){const[r,n]=t.split("-").map(Number);if(r<e||n>s)throw new Error(`Value out of range: ${r}-${n} (expected ${e}-${s})`);for(let t=r;t<=n;t+=o)i.add(t)}else{const r=parseInt(t,10);if(r<e||r>s)throw new Error(`Value out of range: ${r} (expected ${e}-${s})`);for(let t=r;t<=s;t+=o)i.add(t)}}else if(n.includes("-")){const[t,r]=n.split("-").map(Number);if(t<e||r>s)throw new Error(`Value out of range: ${t}-${r} (expected ${e}-${s})`);for(let e=t;e<=r;e++)i.add(e)}else{const t=parseInt(n,10);if(t<e||t>s)throw new Error(`Value out of range: ${t} (expected ${e}-${s})`);i.add(t)}return Array.from(i).sort((t,e)=>t-e)}function o(t){const e=t.trim().split(/\s+/);let s,i,r,o,a,l;if(5===e.length)s=[0],[i,r,o,a,l]=[n(e[0],0,59),n(e[1],0,23),n(e[2],1,31),n(e[3],1,12),n(e[4],0,6)];else{if(6!==e.length)throw new Error(`Invalid cron expression: expected 5 or 6 fields, got ${e.length}`);[s,i,r,o,a,l]=[n(e[0],0,59),n(e[1],0,59),n(e[2],0,23),n(e[3],1,31),n(e[4],1,12),n(e[5],0,6)]}return{second:s,minute:i,hour:r,dayOfMonth:o,month:a,dayOfWeek:l}}function a(t,e){const s=t.getSeconds(),i=t.getMinutes(),r=t.getHours(),n=t.getDate(),o=t.getMonth()+1,a=t.getDay();return e.second.includes(s)&&e.minute.includes(i)&&e.hour.includes(r)&&e.month.includes(o)&&(e.dayOfMonth.includes(n)||e.dayOfWeek.includes(a))}function l(t){const e=t.match(/^(\d+)(s|m|h|d)$/);if(e){const t=parseInt(e[1],10);let s=1e3;switch(e[2]){case"s":s=1e3;break;case"m":s=6e4;break;case"h":s=36e5;break;case"d":s=864e5}return{type:"interval",value:t*s}}try{return function(t){try{o(t)}catch(e){throw new Error(`Invalid cron expression: ${t}`)}}(t),{type:"cron",value:t}}catch(s){throw new Error(`无效的调度格式: "${t}". 必须是有效的 Cron 表达式或间隔字符串 (例如 "10s")。`)}}function c(t,e){let s;if(s="string"==typeof t?l(t):t,"interval"===s.type){const t=s.value,i=(null==e?void 0:e.lastRun)||Date.now();return new Date(i+t)}{const t=s.value;try{return function(t){var e,s,i;const r=o(t);let n=new Date((new Date).getTime()+1e3);n.setMilliseconds(0);let l=0;for(;l<126144e3;){if(a(n,r))return n;const t=n.getSeconds(),o=n.getMinutes(),c=n.getHours();if(!r.second.includes(t)){const s=null!=(e=r.second.find(e=>e>t))?e:r.second[0];s>t?n.setSeconds(s):n.setMinutes(o+1,s),n.setMilliseconds(0),l++;continue}if(!r.minute.includes(o)){const t=null!=(s=r.minute.find(t=>t>o))?s:r.minute[0];t>o?n.setMinutes(t,r.second[0]):n.setHours(c+1,t,r.second[0]),n.setMilliseconds(0),l++;continue}if(!r.hour.includes(c)){const t=null!=(i=r.hour.find(t=>t>c))?i:r.hour[0];t>c||n.setDate(n.getDate()+1),n.setHours(t,r.minute[0],r.second[0]),n.setMilliseconds(0),l++;continue}n=new Date(n.getTime()+1e3),l++}throw new Error(`Could not find next run time for cron expression: ${t}`)}(t,null==e||e.timezone)}catch(i){throw new Error(`无法计算下一次 Cron 运行时间: ${t}`)}}}class u{static getDelay(t,e){if(!e)return-1;const{maxAttempts:s,initialDelay:i,factor:r=2}=e;return t>=s?-1:i*Math.pow(r,t)}}let d=class{constructor(t,s={},i){e(this,"registry"),e(this,"config"),e(this,"defaultTimerStrategy"),e(this,"timerStrategyFactory"),e(this,"taskTimerStrategies"),e(this,"running"),e(this,"timers"),e(this,"listeners"),e(this,"eventListeners"),this.registry=new r,this.defaultTimerStrategy=t,this.timerStrategyFactory=i,this.taskTimerStrategies=new Map,this.config={debug:!1,maxHistory:50,...s},this.running=!1,this.timers=new Map,this.listeners=[],this.eventListeners=new Map,this.config.plugins&&Array.isArray(this.config.plugins)&&this.config.plugins.forEach(t=>{try{this.log(`Initializing plugin: ${t.name}`),t.init(this)}catch(e){console.warn(`[HyperScheduler] Failed to initialize plugin ${t.name}:`,e)}})}subscribe(t){return this.listeners.push(t),()=>{this.listeners=this.listeners.filter(e=>e!==t)}}on(t,e){return this.eventListeners.has(t)||this.eventListeners.set(t,new Set),this.eventListeners.get(t).add(e),()=>{var s;null==(s=this.eventListeners.get(t))||s.delete(e)}}emit(t,e){const s=this.eventListeners.get(t);s&&s.forEach(t=>t(e))}getTimerStrategy(t){var e;const s=null==(e=t.options)?void 0:e.driver,i=this.config.driver,r=s||i;if(!r||!this.timerStrategyFactory)return this.defaultTimerStrategy;const n=`${t.id}_${r}`;if(this.taskTimerStrategies.has(n))return this.taskTimerStrategies.get(n);const o=this.timerStrategyFactory(r);return this.taskTimerStrategies.set(n,o),o}notify(){if(this.listeners.length>0){const t=this.registry.getAllTasks();this.listeners.forEach(e=>e(t))}}createTask(t){var e;!function(t){if(!t||"string"!=typeof t||""===t.trim())throw new Error("Task ID must be a non-empty string.")}(t.id),l(t.schedule);const r={...t,tags:t.tags||[],status:s.STOPPED,history:[],executionCount:0};this.registry.addTask(r),this.log(`Task created: ${r.id}`),this.emit(i.TASK_REGISTERED,{taskId:r.id,task:r}),this.notify(),this.running&&(r.status=s.IDLE,(null==(e=r.options)?void 0:e.runImmediately)&&this.triggerTask(r.id),this.scheduleTask(r))}deleteTask(t){this.stopTask(t);const e=this.registry.deleteTask(t);return e&&(this.log(`Task deleted: ${t}`),this.emit(i.TASK_REMOVED,{taskId:t}),this.notify()),e}startTask(t){const e=this.registry.getTask(t);if(!e)throw new Error(`Task not found: ${t}`);if(e.status===s.RUNNING)return;const r=this.timers.get(t);r&&(this.getTimerStrategy(e).cancel(r),this.timers.delete(t)),e.status=s.IDLE,this.log(`Starting task: ${t}`),this.emit(i.TASK_STARTED,{taskId:t,task:e}),this.notify(),this.scheduleTaskForce(e)}scheduleTaskForce(t){var e;try{const s=c(t.schedule,{timezone:(null==(e=t.options)?void 0:e.timezone)||this.config.timezone,lastRun:t.lastRun});t.nextRun=s.getTime();const i=Date.now(),r=Math.max(0,s.getTime()-i);this.log(`Scheduling task ${t.id} for ${s.toISOString()} (in ${r}ms)`);const n=this.getTimerStrategy(t).schedule(()=>{this.executeTaskIndividual(t)},r);this.timers.set(t.id,n)}catch(i){this.log(`Error scheduling task ${t.id}: ${i}`),t.status=s.ERROR,this.notify()}}async executeTaskIndividual(t,e=0){var r,n;if(this.timers.delete(t.id),t.status===s.STOPPED)return;t.status=s.RUNNING,t.lastRun=Date.now(),t.executionCount=(t.executionCount||0)+1;const o=Date.now();this.log(`Executing task: ${t.id} (Attempt ${e})`),this.emit(i.TASK_STARTED,{taskId:t.id,task:t}),this.notify();try{await t.handler();const e=Date.now()-o;this.recordHistory(t,{timestamp:o,duration:e,success:!0}),t.status=s.IDLE,this.log(`Task execution success: ${t.id}`),this.emit(i.TASK_COMPLETED,{taskId:t.id,task:t,duration:e}),this.notify(),this.scheduleTaskForce(t)}catch(a){const c=Date.now()-o;if(this.recordHistory(t,{timestamp:o,duration:c,success:!1,error:a.message}),this.log(`Task execution failed: ${t.id} - ${a.message}`),this.emit(i.TASK_FAILED,{taskId:t.id,task:t,error:a.message,duration:c}),null==(r=t.options)?void 0:r.onError)try{t.options.onError(a,t.id)}catch(l){this.log(`onError callback failed: ${l}`)}const d=u.getDelay(e,null==(n=t.options)?void 0:n.retry);if(d>=0){this.log(`Retrying task ${t.id} in ${d}ms (Attempt ${e+1})`);const i=this.getTimerStrategy(t).schedule(()=>{this.executeTaskIndividual(t,e+1)},d);this.timers.set(t.id,i),t.status=s.ERROR,this.notify()}else t.status=s.ERROR,this.notify(),this.scheduleTaskForce(t)}}stopTask(t){const e=this.registry.getTask(t),r=this.timers.get(t);r&&e?(this.getTimerStrategy(e).cancel(r),this.timers.delete(t)):r&&(this.defaultTimerStrategy.cancel(r),this.timers.delete(t)),e&&(e.status=s.STOPPED,this.log(`Task stopped: ${t}`),this.emit(i.TASK_STOPPED,{taskId:t,task:e}),this.notify())}getTask(t){return this.registry.getTask(t)}getAllTasks(t){return t?this.registry.getTasksByNamespace(t):this.registry.getAllTasks()}isRunning(){return this.running}getTaskDriver(t){var e;const s=this.registry.getTask(t);return s?(null==(e=s.options)?void 0:e.driver)||this.config.driver||"worker":this.config.driver||"worker"}getGlobalDriver(){return this.config.driver||"worker"}async triggerTask(t){const e=this.getTask(t);if(!e)return;if(e.status===s.RUNNING)return;const r=e.status;e.status=s.RUNNING,e.lastRun=Date.now(),e.executionCount=(e.executionCount||0)+1;const n=Date.now();this.log(`Triggering task: ${e.id}`),this.emit(i.TASK_STARTED,{taskId:e.id,task:e}),this.notify();try{await e.handler();const t=Date.now()-n;this.recordHistory(e,{timestamp:n,duration:t,success:!0}),e.status=r,this.log(`Task trigger success: ${e.id}`),this.emit(i.TASK_COMPLETED,{taskId:e.id,task:e,duration:t}),this.notify()}catch(o){const t=Date.now()-n;this.recordHistory(e,{timestamp:n,duration:t,success:!1,error:o.message}),this.log(`Task trigger failed: ${e.id} - ${o.message}`),this.emit(i.TASK_FAILED,{taskId:e.id,task:e,error:o.message,duration:t}),e.status=r,this.notify()}}start(t){if(!t&&this.running)return;this.log(t?`Scheduler starting for scope: ${t}`:"Scheduler started"),this.emit(i.SCHEDULER_STARTED,{running:!0,scope:t});(t?this.registry.getTasksByNamespace(t):this.registry.getAllTasks()).forEach(t=>{var e;t.status===s.STOPPED&&(t.status=s.IDLE,this.emit(i.TASK_UPDATED,{taskId:t.id,task:t})),t.status!==s.RUNNING&&((null==(e=t.options)?void 0:e.runImmediately)&&this.triggerTask(t.id),this.scheduleTask(t))}),t||(this.running=!0),this.notify()}stop(t){if(!t&&!this.running)return;this.log(t?`Scheduler stopping for scope: ${t}`:"Scheduler stopped"),this.emit(i.SCHEDULER_STOPPED,{running:!1,scope:t});(t?this.registry.getTasksByNamespace(t):this.registry.getAllTasks()).forEach(t=>{const e=this.timers.get(t.id);e&&(this.getTimerStrategy(t).cancel(e),this.timers.delete(t.id)),t.status!==s.STOPPED&&(t.status=s.STOPPED,this.emit(i.TASK_UPDATED,{taskId:t.id,task:t}))}),t||(this.running=!1),this.notify()}scheduleTask(t){var e;try{const s=c(t.schedule,{timezone:(null==(e=t.options)?void 0:e.timezone)||this.config.timezone,lastRun:t.lastRun});t.nextRun=s.getTime();const i=Date.now(),r=Math.max(0,s.getTime()-i);this.log(`Scheduling task ${t.id} for ${s.toISOString()} (in ${r}ms)`);const n=this.getTimerStrategy(t).schedule(()=>{this.executeTask(t)},r);this.timers.set(t.id,n)}catch(i){this.log(`Error scheduling task ${t.id}: ${i}`),t.status=s.ERROR}}async executeTask(t,e=0,r=!1){var n,o;if(this.timers.delete(t.id),!r&&t.status===s.STOPPED)return;t.status=s.RUNNING,t.lastRun=Date.now(),t.executionCount=(t.executionCount||0)+1;const a=Date.now();this.log(`Executing task: ${t.id} (Attempt ${e})`),this.emit(i.TASK_STARTED,{taskId:t.id,task:t}),this.notify();try{await t.handler();const e=Date.now()-a;this.recordHistory(t,{timestamp:a,duration:e,success:!0}),t.status=s.IDLE,this.log(`Task execution success: ${t.id}`),this.emit(i.TASK_COMPLETED,{taskId:t.id,task:t,duration:e}),this.notify(),this.scheduleTask(t)}catch(l){const r=Date.now()-a;if(this.recordHistory(t,{timestamp:a,duration:r,success:!1,error:l.message}),this.log(`Task execution failed: ${t.id} - ${l.message}`),this.emit(i.TASK_FAILED,{taskId:t.id,task:t,error:l.message,duration:r}),null==(n=t.options)?void 0:n.onError)try{t.options.onError(l,t.id)}catch(c){this.log(`onError callback failed: ${c}`)}const d=u.getDelay(e,null==(o=t.options)?void 0:o.retry);if(d>=0){this.log(`Retrying task ${t.id} in ${d}ms (Attempt ${e+1})`);const i=this.getTimerStrategy(t).schedule(()=>{this.executeTask(t,e+1)},d);this.timers.set(t.id,i),t.status=s.ERROR,this.notify()}else t.status=s.ERROR,this.notify(),this.scheduleTask(t)}}recordHistory(t,e){t.history.unshift(e),this.config.maxHistory&&t.history.length>this.config.maxHistory&&t.history.pop()}log(t){this.config.debug&&console.log(`[HyperScheduler] ${t}`)}};class h{schedule(t,e){return setTimeout(t,e)}cancel(t){clearTimeout(t)}}const g="IWZ1bmN0aW9uKCl7InVzZSBzdHJpY3QiO2NvbnN0IGU9bmV3IE1hcDtzZWxmLm9ubWVzc2FnZT1zPT57Y29uc3R7aWQ6dCxkZWxheTpjLHR5cGU6bH09cy5kYXRhO2lmKCJzY2hlZHVsZSI9PT1sKXtjb25zdCBzPXNlbGYuc2V0VGltZW91dCgoKT0+e3NlbGYucG9zdE1lc3NhZ2Uoe2lkOnQsdHlwZToidGljayJ9KSxlLmRlbGV0ZSh0KX0sYyk7ZS5zZXQodCxzKX1lbHNlIGlmKCJjYW5jZWwiPT09bCl7Y29uc3Qgcz1lLmdldCh0KTt2b2lkIDAhPT1zJiYoc2VsZi5jbGVhclRpbWVvdXQocyksZS5kZWxldGUodCkpfX19KCk7Cg==",m="undefined"!=typeof self&&self.Blob&&new Blob([(k=g,Uint8Array.from(atob(k),t=>t.charCodeAt(0)))],{type:"text/javascript;charset=utf-8"});var k;function f(t){let e;try{if(e=m&&(self.URL||self.webkitURL).createObjectURL(m),!e)throw"";const s=new Worker(e,{name:null==t?void 0:t.name});return s.addEventListener("error",()=>{(self.URL||self.webkitURL).revokeObjectURL(e)}),s}catch(s){return new Worker("data:text/javascript;base64,"+g,{name:null==t?void 0:t.name})}finally{e&&(self.URL||self.webkitURL).revokeObjectURL(e)}}class T{constructor(){e(this,"worker"),e(this,"callbacks"),e(this,"nextId"),this.worker=void 0!==f?new f:{postMessage:()=>{},onmessage:null,terminate:()=>{},addEventListener:()=>{},removeEventListener:()=>{},dispatchEvent:()=>!1},this.callbacks=new Map,this.nextId=1,this.worker.onmessage=t=>{const{id:e,type:s}=t.data;if("tick"===s){const t=this.callbacks.get(e);t&&(t(),this.callbacks.delete(e))}}}schedule(t,e){const s=this.nextId++;return this.callbacks.set(s,t),this.worker.postMessage({id:s,delay:e,type:"schedule"}),s}cancel(t){this.worker.postMessage({id:t,type:"cancel"}),this.callbacks.delete(t)}}class p{schedule(t,e){return window.setTimeout(t,e)}cancel(t){window.clearTimeout(t)}}const y="undefined"!=typeof window&&void 0!==window.document;let E=null,S=null;exports.CoreScheduler=d,exports.DevTools=class{constructor(t={}){e(this,"name","DevTools"),e(this,"options"),this.options=t}init(t){"undefined"!=typeof window&&void 0!==window.document&&this.mount(t)}async mount(t){try{await Promise.resolve().then(()=>require("./devtools-Bxtz0rO_.cjs")),await customElements.whenDefined("hs-devtools"),this.setupElement(t)}catch(e){console.error("[DevTools] Failed to mount:",e)}}setupElement(t){try{let e=document.querySelector("hs-devtools");e&&e.remove(),e=document.createElement("hs-devtools");const i=this.options;console.log("[DevTools Plugin] options:",JSON.stringify(i)),i.theme&&e.setAttribute("theme",i.theme),i.dockPosition&&e.setAttribute("dock",i.dockPosition),i.language&&e.setAttribute("language",i.language),i.defaultZoom&&e.setAttribute("default-zoom",i.defaultZoom.toString()),i.trigger&&(i.trigger.backgroundColor&&e.setAttribute("trigger-bg",i.trigger.backgroundColor),i.trigger.textColor&&e.setAttribute("trigger-color",i.trigger.textColor),i.trigger.position&&e.setAttribute("trigger-position",i.trigger.position)),console.log("[DevTools Plugin] attributes set:",e.getAttribute("dock"),e.getAttribute("trigger-position")),document.body.appendChild(e),"function"==typeof e.setScheduler?e.setScheduler({getTasks:()=>t.getAllTasks().map(e=>{var i;return{id:e.id,status:e.status,lastRun:e.lastRun||null,nextRun:e.nextRun||null,executionCount:e.executionCount||0,schedule:e.schedule,tags:e.tags||[],error:e.status===s.ERROR?"Execution failed":null,driver:t.getTaskDriver(e.id),namespace:(null==(i=e.options)?void 0:i.namespace)||"default"}}),on:(e,s)=>t.on(e,s),isRunning:()=>t.isRunning(),trigger:e=>t.triggerTask(e),pause:e=>t.stopTask(e),resume:e=>t.startTask(e),remove:e=>t.deleteTask(e)}):console.warn("[DevTools] hs-devtools element does not have setScheduler method.")}catch(e){console.error("[DevTools] Failed to setup element:",e)}}},exports.Scheduler=class extends d{constructor(t){super(function(t){if(y)return"main"===((null==t?void 0:t.driver)||"worker")?(S||(S=new p),S):(E||(E=new T),E);return new h}(t),t,function(){if(y)return t=>"main"===t?(S||(S=new p),S):(E||(E=new T),E)}())}},exports.SchedulerEvents=i,exports.TaskStatus=s;
|
package/dist/index.js
CHANGED
|
@@ -19,9 +19,12 @@ const SchedulerEvents = {
|
|
|
19
19
|
SCHEDULER_STOPPED: "scheduler_stopped"
|
|
20
20
|
};
|
|
21
21
|
class TaskRegistry {
|
|
22
|
+
// 命名空间 -> Set<任务ID>
|
|
22
23
|
constructor() {
|
|
23
24
|
__publicField(this, "tasks");
|
|
25
|
+
__publicField(this, "namespaceIndex");
|
|
24
26
|
this.tasks = /* @__PURE__ */ new Map();
|
|
27
|
+
this.namespaceIndex = /* @__PURE__ */ new Map();
|
|
25
28
|
}
|
|
26
29
|
/**
|
|
27
30
|
* 注册一个新任务。
|
|
@@ -29,10 +32,16 @@ class TaskRegistry {
|
|
|
29
32
|
* @throws Error 如果 ID 已存在
|
|
30
33
|
*/
|
|
31
34
|
addTask(task) {
|
|
35
|
+
var _a, _b;
|
|
32
36
|
if (this.tasks.has(task.id)) {
|
|
33
37
|
throw new Error(`Task with ID "${task.id}" already exists.`);
|
|
34
38
|
}
|
|
35
39
|
this.tasks.set(task.id, task);
|
|
40
|
+
const namespace = ((_a = task.options) == null ? void 0 : _a.namespace) || "default";
|
|
41
|
+
if (!this.namespaceIndex.has(namespace)) {
|
|
42
|
+
this.namespaceIndex.set(namespace, /* @__PURE__ */ new Set());
|
|
43
|
+
}
|
|
44
|
+
(_b = this.namespaceIndex.get(namespace)) == null ? void 0 : _b.add(task.id);
|
|
36
45
|
}
|
|
37
46
|
/**
|
|
38
47
|
* 根据 ID 获取任务。
|
|
@@ -48,6 +57,16 @@ class TaskRegistry {
|
|
|
48
57
|
* @returns 是否删除成功
|
|
49
58
|
*/
|
|
50
59
|
deleteTask(id) {
|
|
60
|
+
var _a, _b, _c;
|
|
61
|
+
const task = this.tasks.get(id);
|
|
62
|
+
if (!task) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
const namespace = ((_a = task.options) == null ? void 0 : _a.namespace) || "default";
|
|
66
|
+
(_b = this.namespaceIndex.get(namespace)) == null ? void 0 : _b.delete(id);
|
|
67
|
+
if (((_c = this.namespaceIndex.get(namespace)) == null ? void 0 : _c.size) === 0) {
|
|
68
|
+
this.namespaceIndex.delete(namespace);
|
|
69
|
+
}
|
|
51
70
|
return this.tasks.delete(id);
|
|
52
71
|
}
|
|
53
72
|
/**
|
|
@@ -58,10 +77,23 @@ class TaskRegistry {
|
|
|
58
77
|
return Array.from(this.tasks.values());
|
|
59
78
|
}
|
|
60
79
|
/**
|
|
61
|
-
*
|
|
80
|
+
* 根据命名空间获取所有任务。
|
|
81
|
+
* @param namespace 命名空间名称
|
|
82
|
+
* @returns 该命名空间下的任务数组
|
|
83
|
+
*/
|
|
84
|
+
getTasksByNamespace(namespace) {
|
|
85
|
+
const taskIds = this.namespaceIndex.get(namespace);
|
|
86
|
+
if (!taskIds) {
|
|
87
|
+
return [];
|
|
88
|
+
}
|
|
89
|
+
return Array.from(taskIds).map((id) => this.tasks.get(id)).filter(Boolean);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* 清空所有任务和索引。
|
|
62
93
|
*/
|
|
63
94
|
clear() {
|
|
64
95
|
this.tasks.clear();
|
|
96
|
+
this.namespaceIndex.clear();
|
|
65
97
|
}
|
|
66
98
|
}
|
|
67
99
|
function validateId(id) {
|
|
@@ -164,6 +196,7 @@ function matchesCron(date, fields) {
|
|
|
164
196
|
return fields.second.includes(second) && fields.minute.includes(minute) && fields.hour.includes(hour) && fields.month.includes(month) && (fields.dayOfMonth.includes(dayOfMonth) || fields.dayOfWeek.includes(dayOfWeek));
|
|
165
197
|
}
|
|
166
198
|
function getNextRun$1(expression, _timezone) {
|
|
199
|
+
var _a, _b, _c;
|
|
167
200
|
const fields = parseCronExpression(expression);
|
|
168
201
|
const now = /* @__PURE__ */ new Date();
|
|
169
202
|
let candidate = new Date(now.getTime() + 1e3);
|
|
@@ -178,7 +211,7 @@ function getNextRun$1(expression, _timezone) {
|
|
|
178
211
|
const minute = candidate.getMinutes();
|
|
179
212
|
const hour = candidate.getHours();
|
|
180
213
|
if (!fields.second.includes(second)) {
|
|
181
|
-
const nextSecond = fields.second.find((s) => s > second)
|
|
214
|
+
const nextSecond = (_a = fields.second.find((s) => s > second)) != null ? _a : fields.second[0];
|
|
182
215
|
if (nextSecond > second) {
|
|
183
216
|
candidate.setSeconds(nextSecond);
|
|
184
217
|
} else {
|
|
@@ -189,7 +222,7 @@ function getNextRun$1(expression, _timezone) {
|
|
|
189
222
|
continue;
|
|
190
223
|
}
|
|
191
224
|
if (!fields.minute.includes(minute)) {
|
|
192
|
-
const nextMinute = fields.minute.find((m) => m > minute)
|
|
225
|
+
const nextMinute = (_b = fields.minute.find((m) => m > minute)) != null ? _b : fields.minute[0];
|
|
193
226
|
if (nextMinute > minute) {
|
|
194
227
|
candidate.setMinutes(nextMinute, fields.second[0]);
|
|
195
228
|
} else {
|
|
@@ -200,7 +233,7 @@ function getNextRun$1(expression, _timezone) {
|
|
|
200
233
|
continue;
|
|
201
234
|
}
|
|
202
235
|
if (!fields.hour.includes(hour)) {
|
|
203
|
-
const nextHour = fields.hour.find((h) => h > hour)
|
|
236
|
+
const nextHour = (_c = fields.hour.find((h) => h > hour)) != null ? _c : fields.hour[0];
|
|
204
237
|
if (nextHour > hour) {
|
|
205
238
|
candidate.setHours(nextHour, fields.minute[0], fields.second[0]);
|
|
206
239
|
} else {
|
|
@@ -399,6 +432,7 @@ let Scheduler$1 = class Scheduler {
|
|
|
399
432
|
* @param definition 任务定义
|
|
400
433
|
*/
|
|
401
434
|
createTask(definition) {
|
|
435
|
+
var _a;
|
|
402
436
|
validateId(definition.id);
|
|
403
437
|
parseSchedule(definition.schedule);
|
|
404
438
|
const task = {
|
|
@@ -415,6 +449,9 @@ let Scheduler$1 = class Scheduler {
|
|
|
415
449
|
this.notify();
|
|
416
450
|
if (this.running) {
|
|
417
451
|
task.status = TaskStatus.IDLE;
|
|
452
|
+
if ((_a = task.options) == null ? void 0 : _a.runImmediately) {
|
|
453
|
+
this.triggerTask(task.id);
|
|
454
|
+
}
|
|
418
455
|
this.scheduleTask(task);
|
|
419
456
|
}
|
|
420
457
|
}
|
|
@@ -572,9 +609,14 @@ let Scheduler$1 = class Scheduler {
|
|
|
572
609
|
return this.registry.getTask(id);
|
|
573
610
|
}
|
|
574
611
|
/**
|
|
575
|
-
*
|
|
612
|
+
* 获取所有任务,可按命名空间筛选。
|
|
613
|
+
* @param namespace 可选的命名空间名称
|
|
614
|
+
* @returns 任务数组
|
|
576
615
|
*/
|
|
577
|
-
getAllTasks() {
|
|
616
|
+
getAllTasks(namespace) {
|
|
617
|
+
if (namespace) {
|
|
618
|
+
return this.registry.getTasksByNamespace(namespace);
|
|
619
|
+
}
|
|
578
620
|
return this.registry.getAllTasks();
|
|
579
621
|
}
|
|
580
622
|
/**
|
|
@@ -646,50 +688,56 @@ let Scheduler$1 = class Scheduler {
|
|
|
646
688
|
* 启动调度器。
|
|
647
689
|
* 开始处理所有任务(除了手动停止的任务)。
|
|
648
690
|
*/
|
|
649
|
-
start() {
|
|
650
|
-
if (this.running) return;
|
|
651
|
-
this.
|
|
652
|
-
this.
|
|
653
|
-
this.
|
|
654
|
-
|
|
691
|
+
start(scope) {
|
|
692
|
+
if (!scope && this.running) return;
|
|
693
|
+
this.log(scope ? `Scheduler starting for scope: ${scope}` : "Scheduler started");
|
|
694
|
+
this.emit(SchedulerEvents.SCHEDULER_STARTED, { running: true, scope });
|
|
695
|
+
const tasksToStart = scope ? this.registry.getTasksByNamespace(scope) : this.registry.getAllTasks();
|
|
696
|
+
tasksToStart.forEach((task) => {
|
|
697
|
+
var _a;
|
|
655
698
|
if (task.status === TaskStatus.STOPPED) {
|
|
656
699
|
task.status = TaskStatus.IDLE;
|
|
657
700
|
this.emit(SchedulerEvents.TASK_UPDATED, { taskId: task.id, task });
|
|
658
701
|
}
|
|
659
702
|
if (task.status !== TaskStatus.RUNNING) {
|
|
703
|
+
if ((_a = task.options) == null ? void 0 : _a.runImmediately) {
|
|
704
|
+
this.triggerTask(task.id);
|
|
705
|
+
}
|
|
660
706
|
this.scheduleTask(task);
|
|
661
707
|
}
|
|
662
708
|
});
|
|
709
|
+
if (!scope) {
|
|
710
|
+
this.running = true;
|
|
711
|
+
}
|
|
663
712
|
this.notify();
|
|
664
713
|
}
|
|
665
714
|
/**
|
|
666
715
|
* 停止调度器。
|
|
667
716
|
* 取消所有正在等待的定时器。
|
|
668
717
|
*/
|
|
669
|
-
stop() {
|
|
670
|
-
this.running
|
|
671
|
-
this.log("Scheduler stopped");
|
|
672
|
-
this.emit(SchedulerEvents.SCHEDULER_STOPPED, { running: false });
|
|
673
|
-
this.
|
|
674
|
-
|
|
675
|
-
|
|
718
|
+
stop(scope) {
|
|
719
|
+
if (!scope && !this.running) return;
|
|
720
|
+
this.log(scope ? `Scheduler stopping for scope: ${scope}` : "Scheduler stopped");
|
|
721
|
+
this.emit(SchedulerEvents.SCHEDULER_STOPPED, { running: false, scope });
|
|
722
|
+
const tasksToStop = scope ? this.registry.getTasksByNamespace(scope) : this.registry.getAllTasks();
|
|
723
|
+
tasksToStop.forEach((task) => {
|
|
724
|
+
const handle = this.timers.get(task.id);
|
|
725
|
+
if (handle) {
|
|
676
726
|
this.getTimerStrategy(task).cancel(handle);
|
|
677
|
-
|
|
678
|
-
this.defaultTimerStrategy.cancel(handle);
|
|
727
|
+
this.timers.delete(task.id);
|
|
679
728
|
}
|
|
680
|
-
});
|
|
681
|
-
this.timers.clear();
|
|
682
|
-
this.registry.getAllTasks().forEach((task) => {
|
|
683
729
|
if (task.status !== TaskStatus.STOPPED) {
|
|
684
730
|
task.status = TaskStatus.STOPPED;
|
|
685
731
|
this.emit(SchedulerEvents.TASK_UPDATED, { taskId: task.id, task });
|
|
686
732
|
}
|
|
687
733
|
});
|
|
734
|
+
if (!scope) {
|
|
735
|
+
this.running = false;
|
|
736
|
+
}
|
|
688
737
|
this.notify();
|
|
689
738
|
}
|
|
690
739
|
scheduleTask(task) {
|
|
691
740
|
var _a;
|
|
692
|
-
if (!this.running && task.status !== TaskStatus.RUNNING) return;
|
|
693
741
|
try {
|
|
694
742
|
const nextRun = getNextRun(task.schedule, {
|
|
695
743
|
timezone: ((_a = task.options) == null ? void 0 : _a.timezone) || this.config.timezone,
|
|
@@ -713,7 +761,7 @@ let Scheduler$1 = class Scheduler {
|
|
|
713
761
|
async executeTask(task, attempt = 0, force = false) {
|
|
714
762
|
var _a, _b;
|
|
715
763
|
this.timers.delete(task.id);
|
|
716
|
-
if (!force &&
|
|
764
|
+
if (!force && task.status === TaskStatus.STOPPED) return;
|
|
717
765
|
task.status = TaskStatus.RUNNING;
|
|
718
766
|
task.lastRun = Date.now();
|
|
719
767
|
task.executionCount = (task.executionCount || 0) + 1;
|
|
@@ -888,7 +936,7 @@ class DevTools {
|
|
|
888
936
|
}
|
|
889
937
|
async mount(scheduler) {
|
|
890
938
|
try {
|
|
891
|
-
await import("./devtools-
|
|
939
|
+
await import("./devtools-ByJU-Gv1.js");
|
|
892
940
|
await customElements.whenDefined("hs-devtools");
|
|
893
941
|
this.setupElement(scheduler);
|
|
894
942
|
} catch (e) {
|
|
@@ -918,17 +966,22 @@ class DevTools {
|
|
|
918
966
|
if (typeof el.setScheduler === "function") {
|
|
919
967
|
el.setScheduler({
|
|
920
968
|
getTasks: () => {
|
|
921
|
-
return scheduler.getAllTasks().map((task) =>
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
969
|
+
return scheduler.getAllTasks().map((task) => {
|
|
970
|
+
var _a;
|
|
971
|
+
return {
|
|
972
|
+
id: task.id,
|
|
973
|
+
status: task.status,
|
|
974
|
+
lastRun: task.lastRun || null,
|
|
975
|
+
nextRun: task.nextRun || null,
|
|
976
|
+
executionCount: task.executionCount || 0,
|
|
977
|
+
schedule: task.schedule,
|
|
978
|
+
tags: task.tags || [],
|
|
979
|
+
error: task.status === TaskStatus.ERROR ? "Execution failed" : null,
|
|
980
|
+
driver: scheduler.getTaskDriver(task.id),
|
|
981
|
+
namespace: ((_a = task.options) == null ? void 0 : _a.namespace) || "default"
|
|
982
|
+
// 添加 namespace
|
|
983
|
+
};
|
|
984
|
+
});
|
|
932
985
|
},
|
|
933
986
|
on: (evt, handler) => {
|
|
934
987
|
return scheduler.on(evt, handler);
|