Skip to content

定时任务

在node.js里定时执行指令

安装

bash
pnpm add @aomex/cron

使用

定时任务依赖指令,因此请先编写指令。

typescript
// src/cli.ts
import { ConsoleApp } from '@aomex/core';
import { commanders } from '@aomex/cron';
import { crons } from '@aomex/cron';

const app = new ConsoleApp({
  mount: [
    crons({ commanders: './src/commanders' }),
    commanders('./src/commanders'),
  ],
});

携带指令

输入npx aomex -h可以查看所有指令和描述

指令描述
aomex cron:start启动定时任务
aomex cron:eject导出定时任务列表
aomex cron:stop退出定时任务
aomex cron:stats查看定时任务执行状态

第一个打招呼任务

typescript
// src/commanders/say.ts
import { Commander } from '@aomex/console';
import { cron } from '@aomex/cron';

export const commander = new Commander();

commander.create('say', {
  mount: [
    cron({
      minute: '*/10',
    }),
  ],
  action: (ctx) => {
    console.log('Hello World');
  },
});

启动任务

bash
npx aomex cron:start

每隔10分钟就会有人向我打招呼,真礼貌!

单指令多任务

如果同时要向 唐三 和 小舞 打招呼,是否可行?试试

typescript
// src/commanders/say.ts
import { cron } from '@aomex/cron';
import { Commander, options } from '@aomex/console';

export const commander = new Commander();

commander.create('say', {
  mount: [
    options({
      name: rule.string(),
    }),
    cron({
      minute: '*/10',
      args: ['--name', '唐三'],
    }),
    cron({
      minute: '*/10',
      args: ['--name', '小舞'],
    }),
  ],
  action: (ctx) => {
    const { name } = ctx.options;
    console.log(`Hello ${name}`);
  },
});

定时任务加入参数,再多招呼都能打。

集群

集群服务需通过存储介质共享状态,可以考虑如下介质:

typescript
import { Caching } from '@aomex/cache';
import { redisAdapter } from '@aomex/cache-redis-adapter';

crons({
  cache: new Caching(redisAdapter({ host: 'http://', ... })),
});

任务并发

在集群服务中,每个服务会触发相同的任务,框架默认只允许一个服务通过抢占的形式获得任务并执行。因为并发任务就像多线程操作,读取资源需要设置排斥锁才能保证安全,否则一不留神就会造成业务被多次处理而出问题。

当然,我们也可以通过参数修改这种默认行为,让并发执行成为可能(但是注意加锁):

typescript
// src/commanders/mail.ts
import { Commander } from '@aomex/console';
import { cron } from '@aomex/cron';

export const commander = new Commander();

commander.create('send:mail', {
  mount: [
    cron({
      minute: '*',
      concurrent: Infinity, 
    }),
  ],
  action: async (ctx) => {
    // 加锁,否则可能被其它服务获取
    const mail = await service.findAndLockMail();
    try {
      await service.sendMail(mail);
    } catch {
      await service.unlockMail(mail);
    }
  },
});

现在,所有启动的服务都会每隔一分钟发送一次邮件。