fix(plugin-workflow): remove previous listeners when collection changed in config (#409)
This commit is contained in:
parent
b44753d528
commit
dc05399beb
@ -0,0 +1,48 @@
|
|||||||
|
import { Application } from '@nocobase/server';
|
||||||
|
import Database from '@nocobase/database';
|
||||||
|
import { getApp, sleep } from '..';
|
||||||
|
import { EXECUTION_STATUS } from '../../constants';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
describe('workflow > triggers > collection', () => {
|
||||||
|
let app: Application;
|
||||||
|
let db: Database;
|
||||||
|
let PostRepo;
|
||||||
|
let WorkflowModel;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
app = await getApp();
|
||||||
|
|
||||||
|
db = app.db;
|
||||||
|
WorkflowModel = db.getCollection('workflows').model;
|
||||||
|
PostRepo = db.getCollection('posts').repository;
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => db.close());
|
||||||
|
|
||||||
|
describe('toggle', () => {
|
||||||
|
it('when collection change', async () => {
|
||||||
|
const workflow = await WorkflowModel.create({
|
||||||
|
enabled: true,
|
||||||
|
type: 'collection',
|
||||||
|
config: {
|
||||||
|
mode: 1,
|
||||||
|
collection: 'posts'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await workflow.update({
|
||||||
|
config: {
|
||||||
|
...workflow.config,
|
||||||
|
collection: 'comments'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const post = await PostRepo.create({ values: { title: 't1' } });
|
||||||
|
|
||||||
|
const executions = await workflow.getExecutions();
|
||||||
|
expect(executions.length).toBe(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@ -1,5 +1,5 @@
|
|||||||
import { Database, Model } from '@nocobase/database';
|
import { Database, Model } from '@nocobase/database';
|
||||||
import { HasManyCountAssociationsMixin, HasManyCreateAssociationMixin, HasManyGetAssociationsMixin } from 'sequelize';
|
import { HasManyCountAssociationsMixin, HasManyCreateAssociationMixin, HasManyGetAssociationsMixin, Transactionable } from 'sequelize';
|
||||||
|
|
||||||
import { EXECUTION_STATUS } from '../constants';
|
import { EXECUTION_STATUS } from '../constants';
|
||||||
import ExecutionModel from './Execution';
|
import ExecutionModel from './Execution';
|
||||||
@ -31,7 +31,7 @@ export default class WorkflowModel extends Model {
|
|||||||
|
|
||||||
getTransaction(options) {
|
getTransaction(options) {
|
||||||
if (!this.useTransaction) {
|
if (!this.useTransaction) {
|
||||||
return undefined;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return options.transaction && !options.transaction.finished
|
return options.transaction && !options.transaction.finished
|
||||||
@ -39,7 +39,7 @@ export default class WorkflowModel extends Model {
|
|||||||
: (<typeof WorkflowModel>this.constructor).database.sequelize.transaction();
|
: (<typeof WorkflowModel>this.constructor).database.sequelize.transaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
trigger = async (context: Object, options) => {
|
trigger = async (context: Object, options = {}) => {
|
||||||
// `null` means not to trigger
|
// `null` means not to trigger
|
||||||
if (context === null) {
|
if (context === null) {
|
||||||
return;
|
return;
|
||||||
@ -73,9 +73,11 @@ export default class WorkflowModel extends Model {
|
|||||||
await execution.start({ transaction });
|
await execution.start({ transaction });
|
||||||
|
|
||||||
if (!this.executed) {
|
if (!this.executed) {
|
||||||
await this.update({ executed: true }, { transaction });
|
// NOTE: not to trigger afterUpdate hook here
|
||||||
|
await this.update({ executed: true }, { transaction, hooks: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
if (transaction && (!options.transaction || options.transaction.finished)) {
|
if (transaction && (!options.transaction || options.transaction.finished)) {
|
||||||
await transaction.commit();
|
await transaction.commit();
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ MODE_BITMAP_EVENTS.set(MODE_BITMAP.DESTROY, 'afterDestroy');
|
|||||||
|
|
||||||
|
|
||||||
function getHookId(workflow, type) {
|
function getHookId(workflow, type) {
|
||||||
return `${type}#${workflow.get('id')}`;
|
return `${type}#${workflow.id}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// async function, should return promise
|
// async function, should return promise
|
||||||
@ -43,12 +43,23 @@ function handler(this: WorkflowModel, data: Model, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default class CollectionTrigger implements Trigger {
|
export default class CollectionTrigger implements Trigger {
|
||||||
|
db;
|
||||||
|
|
||||||
events = new Map();
|
events = new Map();
|
||||||
|
|
||||||
|
constructor({ app }) {
|
||||||
|
this.db = app.db;
|
||||||
|
}
|
||||||
|
|
||||||
on(workflow: WorkflowModel) {
|
on(workflow: WorkflowModel) {
|
||||||
const { database } = <typeof WorkflowModel>workflow.constructor;
|
// NOTE: remove previous listener if config updated
|
||||||
|
const prev = workflow.previous();
|
||||||
|
if (prev.config) {
|
||||||
|
this.off({ ...workflow.get(), ...prev });
|
||||||
|
}
|
||||||
|
|
||||||
const { collection, mode } = workflow.config;
|
const { collection, mode } = workflow.config;
|
||||||
const Collection = database.getCollection(collection);
|
const Collection = this.db.getCollection(collection);
|
||||||
if (!Collection) {
|
if (!Collection) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -60,12 +71,12 @@ export default class CollectionTrigger implements Trigger {
|
|||||||
if (!this.events.has(name)) {
|
if (!this.events.has(name)) {
|
||||||
const listener = handler.bind(workflow);
|
const listener = handler.bind(workflow);
|
||||||
this.events.set(name, listener);
|
this.events.set(name, listener);
|
||||||
database.on(event, listener);
|
this.db.on(event, listener);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const listener = this.events.get(name);
|
const listener = this.events.get(name);
|
||||||
if (listener) {
|
if (listener) {
|
||||||
database.off(event, listener);
|
this.db.off(event, listener);
|
||||||
this.events.delete(name);
|
this.events.delete(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -73,9 +84,8 @@ export default class CollectionTrigger implements Trigger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
off(workflow: WorkflowModel) {
|
off(workflow: WorkflowModel) {
|
||||||
const { database } = <typeof WorkflowModel>workflow.constructor;
|
|
||||||
const { collection, mode } = workflow.config;
|
const { collection, mode } = workflow.config;
|
||||||
const Collection = database.getCollection(collection);
|
const Collection = this.db.getCollection(collection);
|
||||||
if (!Collection) {
|
if (!Collection) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -85,7 +95,7 @@ export default class CollectionTrigger implements Trigger {
|
|||||||
if (mode & key) {
|
if (mode & key) {
|
||||||
const listener = this.events.get(name);
|
const listener = this.events.get(name);
|
||||||
if (listener) {
|
if (listener) {
|
||||||
database.off(event, listener);
|
this.db.off(event, listener);
|
||||||
this.events.delete(name);
|
this.events.delete(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,8 @@ export interface Trigger {
|
|||||||
off(workflow: WorkflowModel): void;
|
off(workflow: WorkflowModel): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function({ triggers }) {
|
export default function(plugin) {
|
||||||
triggers.register('collection', new Collection());
|
const { triggers } = plugin;
|
||||||
// triggers.register('schedule', new Schedule());
|
triggers.register('collection', new Collection(plugin));
|
||||||
|
// triggers.register('schedule', new Schedule(plugin));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user