ms/packages/spring/src/task.ts

89 lines
2.6 KiB
TypeScript

import { task, plugin } from '@ccms/api'
import { inject, provideSingleton } from '@ccms/container'
const AtomicBoolean = Java.type("java.util.concurrent.atomic.AtomicBoolean")
const Thread = Java.type('java.lang.Thread')
const ThreadPoolExecutor = Java.type('java.util.concurrent.ThreadPoolExecutor')
const ThreadPoolTaskExecutor = Java.type('org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor')
let executor: any
let tasks: { [key: number]: task.Cancelable } = {}
let taskId = 0
@provideSingleton(task.TaskManager)
export class SpringTaskManager implements task.TaskManager {
@inject(plugin.PluginInstance)
private pluginInstance: any
constructor() {
executor = new ThreadPoolTaskExecutor()
executor.setCorePoolSize(10)
executor.setMaxPoolSize(100)
executor.setQueueCapacity(500)
executor.setKeepAliveSeconds(60)
executor.setThreadNamePrefix("@ccms/spring-")
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy())
executor.initialize()
}
create(func: Function): task.Task {
if (Object.prototype.toString.call(func) !== "[object Function]") { throw TypeError('第一个参数 Task 必须为 function !') }
return new SpringTask(this.pluginInstance, func)
}
callSyncMethod(func: Function): any {
return func()
}
disable() {
Object.values(tasks).forEach((task) => task.cancel())
executor.shutdown();
}
}
export class SpringTask extends task.Task {
public id = taskId++
private running = new AtomicBoolean(true)
run() {
if (this.laterTime > 0) {
try {
Thread.sleep(this.laterTime)
} catch (ex) {
Thread.currentThread().interrupt()
}
}
while (this.running.get()) {
try {
this.func()
} catch (t) {
console.error("Task exec error:", t)
console.ex(t)
}
// If we have a interval of 0 or less, only run once
if (this.interval <= 0) { break }
try {
Thread.sleep(this.interval)
} catch (ex) {
Thread.currentThread().interrupt()
}
}
this.cancel()
}
cancel(): any {
var wasRunning = this.running.getAndSet(false)
if (wasRunning) {
tasks[this.id] = undefined
}
}
submit(): task.Cancelable {
tasks[this.id] = this
executor.execute(this.run.bind(this))
return {
cancel: () => {
return this.cancel()
}
}
}
}