-
Notifications
You must be signed in to change notification settings - Fork 579
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add midway task component (#995)
- Loading branch information
Showing
19 changed files
with
480 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
# Midway-task | ||
|
||
## 简介 | ||
Midway-task是为了能解决任务系列的模块,例如分布式定时任务、延迟任务调度。例如订单2小时后失效、每日定时的数据处理等工作。 | ||
|
||
## 安装方法 | ||
|
||
```bash | ||
tnpm install @midwayjs/task -S | ||
``` | ||
|
||
## 使用方法 | ||
|
||
在Configuration.ts导入子组件 | ||
|
||
```typescript | ||
|
||
import * as task from '@midwayjs/task'; | ||
|
||
@Configuration({ | ||
imports: [task], | ||
importConfigs: [ | ||
join(__dirname, 'config') | ||
] | ||
}) | ||
export class AutoConfiguration{ | ||
} | ||
``` | ||
|
||
配置: | ||
|
||
在 config.default.ts 文件中配置对应的模块信息: | ||
|
||
```typescript | ||
export const taskConfig = { | ||
redis: `redis://127.0.0.1:32768`, | ||
prefix: 'midway-task', | ||
defaultJobOptions: { | ||
repeat: { | ||
tz: "Asia/Shanghai" | ||
} | ||
} | ||
} | ||
``` | ||
|
||
## 业务代码编写方式 | ||
|
||
分布式定时任务: | ||
|
||
```typescript | ||
@Provide() | ||
export class UserService { | ||
@Inject() | ||
helloService: HelloService; | ||
|
||
// 例如下面是每分钟执行一次,并且是分布式任务 | ||
@Task({ | ||
repeat: { cron: '* * * * *'} | ||
}) | ||
async test(){ | ||
console.log(this.helloService.getName()) | ||
} | ||
} | ||
``` | ||
|
||
本地定时任务: | ||
|
||
```typescript | ||
@Provide() | ||
export class UserService { | ||
@Inject() | ||
helloService: HelloService; | ||
|
||
// 例如下面是每分钟执行一次 | ||
@TaskLocal('* * * * * *') | ||
async test(){ | ||
console.log(this.helloService.getName()) | ||
} | ||
} | ||
``` | ||
|
||
定时执行任务: | ||
|
||
```typescript | ||
@Provide() | ||
export class UserService { | ||
@Inject() | ||
helloService: HelloService; | ||
|
||
// 例如下面是每分钟执行一次 | ||
@TaskLocal('* * * * * *') | ||
async test(){ | ||
console.log(this.helloService.getName()) | ||
} | ||
} | ||
``` | ||
|
||
让用户定义任务 | ||
|
||
```typescript | ||
|
||
@Queue() | ||
@Provide() | ||
export class HelloTask{ | ||
|
||
@Inject() | ||
service; | ||
|
||
async excute(params){ | ||
console.log(params); | ||
} | ||
} | ||
``` | ||
|
||
```typescript | ||
import { QueueService } from '@midwayjs/task'; | ||
@Provide() | ||
export class UserTask{ | ||
|
||
@Inject() | ||
service; | ||
|
||
@Inject() | ||
queueService: QueueService; | ||
|
||
async excute(params){ | ||
// 3秒后触发分布式任务调度。 | ||
const xxx = this.queueService.excute(HelloTask, params, {delay: 3000}); | ||
} | ||
} | ||
|
||
``` | ||
## 其他 | ||
|
||
关于task任务的配置: | ||
``` | ||
* * * * * * | ||
┬ ┬ ┬ ┬ ┬ ┬ | ||
│ │ │ │ │ | | ||
│ │ │ │ │ └ day of week (0 - 7) (0 or 7 is Sun) | ||
│ │ │ │ └───── month (1 - 12) | ||
│ │ │ └────────── day of month (1 - 31) | ||
│ │ └─────────────── hour (0 - 23) | ||
│ └──────────────────── minute (0 - 59) | ||
└───────────────────────── second (0 - 59, optional) | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
const path = require('path'); | ||
|
||
module.exports = { | ||
preset: 'ts-jest', | ||
testEnvironment: 'node', | ||
testPathIgnorePatterns: ['<rootDir>/test/fixtures'], | ||
coveragePathIgnorePatterns: ['<rootDir>/test/'], | ||
setupFilesAfterEnv: [path.join(__dirname, 'test/.setup.js')] | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
{ | ||
"name": "@midwayjs/task", | ||
"version": "1.0.0", | ||
"description": "", | ||
"main": "dist/index.js", | ||
"typings": "dist/index.d.ts", | ||
"scripts": { | ||
"build": "midway-bin build -c", | ||
"test": "midway-bin test --ts", | ||
"cov": "midway-bin cov --ts", | ||
"ci": "npm run cov" | ||
}, | ||
"keywords": [], | ||
"author": "", | ||
"files": [ | ||
"dist/**/*.js", | ||
"dist/**/*.d.ts" | ||
], | ||
"license": "MIT", | ||
"devDependencies": { | ||
"@midwayjs/cli": "^1.2.38", | ||
"@midwayjs/core": "^2.3.0", | ||
"@midwayjs/decorator": "^2.3.0", | ||
"@midwayjs/koa": "^2.10.6", | ||
"@midwayjs/mock": "^2.10.6", | ||
"@types/bull": "^3.15.0", | ||
"@types/cron": "^1.7.2", | ||
"@types/jest": "^26.0.10", | ||
"@types/node": "14", | ||
"cross-env": "^6.0.0", | ||
"jest": "^26.4.0", | ||
"mwts": "^1.0.5", | ||
"ts-jest": "^26.2.0", | ||
"typescript": "^4.0.0" | ||
}, | ||
"dependencies": { | ||
"bull": "^3.22.0", | ||
"cron": "^1.8.2" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
export const taskConfig = { | ||
redis: 'redis://127.0.0.1:32768', | ||
prefix: 'midway-task', | ||
defaultJobOptions: { | ||
repeat: { | ||
tz: 'Asia/Shanghai', | ||
}, | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
// src/configuration.ts | ||
import { | ||
App, | ||
Config, | ||
Configuration, | ||
getClassMetadata, | ||
listModule, | ||
} from '@midwayjs/decorator'; | ||
import { join } from 'path'; | ||
import { IMidwayApplication, IMidwayContainer } from '@midwayjs/core'; | ||
import { | ||
MODULE_TASK_KEY, | ||
MODULE_TASK_METADATA, | ||
MODULE_TASK_QUEUE_KEY, | ||
MODULE_TASK_QUEUE_OPTIONS, | ||
MODULE_TASK_TASK_LOCAL_KEY, | ||
MODULE_TASK_TASK_LOCAL_OPTIONS, | ||
} from './const'; | ||
import * as Bull from 'bull'; | ||
import { CronJob } from 'cron'; | ||
|
||
@Configuration({ | ||
namespace: 'task', | ||
importConfigs: [join(__dirname, 'config')], | ||
}) | ||
export class AutoConfiguration { | ||
@App() | ||
app; | ||
|
||
@Config('taskConfig') | ||
taskConfig; | ||
|
||
queueList: any[] = []; | ||
jobList: any[] = []; | ||
|
||
async onReady( | ||
container: IMidwayContainer, | ||
app: IMidwayApplication | ||
): Promise<void> { | ||
await this.loadTask(); | ||
await this.loadLocalTask(); | ||
await this.loadQueue(container); | ||
} | ||
|
||
async onStop() { | ||
this.queueList.map(queue => { | ||
queue.stop(); | ||
}); | ||
this.jobList.map(job => { | ||
job.stop(); | ||
}); | ||
} | ||
|
||
async loadTask() { | ||
const modules = listModule(MODULE_TASK_KEY); | ||
for (const module of modules) { | ||
const rules = getClassMetadata(MODULE_TASK_METADATA, module); | ||
for (const rule of rules) { | ||
const queue = new Bull( | ||
`${rule.name}:${rule.propertyKey}`, | ||
this.taskConfig | ||
); | ||
queue.process(async job => { | ||
const ctx = this.app.createAnonymousContext(); | ||
const service = await ctx.requestContext.getAsync(module); | ||
rule.value.call(service, job.data); | ||
}); | ||
queue.add({}, rule.options); | ||
this.queueList.push(queue); | ||
} | ||
} | ||
} | ||
|
||
async loadLocalTask() { | ||
const modules = listModule(MODULE_TASK_TASK_LOCAL_KEY); | ||
for (const module of modules) { | ||
const rules = getClassMetadata(MODULE_TASK_TASK_LOCAL_OPTIONS, module); | ||
for (const rule of rules) { | ||
const job = new CronJob( | ||
rule.options, | ||
async () => { | ||
const ctx = this.app.createAnonymousContext(); | ||
const service = await ctx.requestContext.getAsync(module); | ||
rule.value.call(service); | ||
}, | ||
null, | ||
true, | ||
this.taskConfig.defaultJobOptions.repeat.tz | ||
); | ||
job.start(); | ||
this.jobList.push(job); | ||
} | ||
} | ||
} | ||
|
||
async loadQueue(container) { | ||
const modules = listModule(MODULE_TASK_QUEUE_KEY); | ||
const queueMap = {}; | ||
const config = JSON.parse(JSON.stringify(this.taskConfig)); | ||
delete config.defaultJobOptions.repeat; | ||
for (const module of modules) { | ||
const rule = getClassMetadata(MODULE_TASK_QUEUE_OPTIONS, module); | ||
const queue = new Bull(`${rule.name}:excute`, config); | ||
queue.process(async job => { | ||
const ctx = this.app.createAnonymousContext(); | ||
const service = await ctx.requestContext.getAsync(module); | ||
await service.excute.call(service, job.data); | ||
}); | ||
queueMap[`${rule.name}:excute`] = queue; | ||
this.queueList.push(queue); | ||
} | ||
container.registerObject('queueMap', queueMap); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
export const MODULE_TASK_KEY = '@midway/task'; | ||
export const MODULE_TASK_METADATA = '@midway/task:task'; | ||
export const MODULE_TASK_TASK_LOCAL_KEY = '@midway/task:task_local'; | ||
export const MODULE_TASK_TASK_LOCAL_OPTIONS = '@midway/task:task_local:options'; | ||
export const MODULE_TASK_QUEUE_KEY = '@midway/task:queue'; | ||
export const MODULE_TASK_QUEUE_OPTIONS = '@midway/task:queue:options'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { saveModule, saveClassMetadata } from '@midwayjs/core'; | ||
import { MODULE_TASK_QUEUE_KEY, MODULE_TASK_QUEUE_OPTIONS } from '../const'; | ||
|
||
export function Queue(options?: any) { | ||
return function (target) { | ||
saveModule(MODULE_TASK_QUEUE_KEY, target); | ||
saveClassMetadata( | ||
MODULE_TASK_QUEUE_OPTIONS, | ||
{ | ||
options, | ||
name: target.constructor.name, | ||
}, | ||
target | ||
); | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { saveModule, attachClassMetadata } from '@midwayjs/core'; | ||
import { MODULE_TASK_KEY, MODULE_TASK_METADATA } from '../const'; | ||
|
||
export function Task(options) { | ||
return function ( | ||
target: any, | ||
propertyKey: string, | ||
descriptor: PropertyDescriptor | ||
) { | ||
saveModule(MODULE_TASK_KEY, target.constructor); | ||
attachClassMetadata( | ||
MODULE_TASK_METADATA, | ||
{ | ||
options, | ||
propertyKey, | ||
value: descriptor.value, | ||
name: target.constructor.name, | ||
}, | ||
target | ||
); | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { saveModule, attachClassMetadata } from '@midwayjs/core'; | ||
import { | ||
MODULE_TASK_TASK_LOCAL_KEY, | ||
MODULE_TASK_TASK_LOCAL_OPTIONS, | ||
} from '../const'; | ||
|
||
export function TaskLocal(options) { | ||
return function ( | ||
target: any, | ||
propertyKey: string, | ||
descriptor: PropertyDescriptor | ||
) { | ||
saveModule(MODULE_TASK_TASK_LOCAL_KEY, target.constructor); | ||
attachClassMetadata( | ||
MODULE_TASK_TASK_LOCAL_OPTIONS, | ||
{ | ||
options, | ||
propertyKey, | ||
value: descriptor.value, | ||
}, | ||
target | ||
); | ||
}; | ||
} |
Oops, something went wrong.