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 { HasManyCountAssociationsMixin, HasManyCreateAssociationMixin, HasManyGetAssociationsMixin } from 'sequelize'; | ||||
| import { HasManyCountAssociationsMixin, HasManyCreateAssociationMixin, HasManyGetAssociationsMixin, Transactionable } from 'sequelize'; | ||||
| 
 | ||||
| import { EXECUTION_STATUS } from '../constants'; | ||||
| import ExecutionModel from './Execution'; | ||||
| @ -31,7 +31,7 @@ export default class WorkflowModel extends Model { | ||||
| 
 | ||||
|   getTransaction(options) { | ||||
|     if (!this.useTransaction) { | ||||
|       return undefined; | ||||
|       return null; | ||||
|     } | ||||
| 
 | ||||
|     return options.transaction && !options.transaction.finished | ||||
| @ -39,7 +39,7 @@ export default class WorkflowModel extends Model { | ||||
|       : (<typeof WorkflowModel>this.constructor).database.sequelize.transaction(); | ||||
|   } | ||||
| 
 | ||||
|   trigger = async (context: Object, options) => { | ||||
|   trigger = async (context: Object, options = {}) => { | ||||
|     // `null` means not to trigger
 | ||||
|     if (context === null) { | ||||
|       return; | ||||
| @ -73,9 +73,11 @@ export default class WorkflowModel extends Model { | ||||
|     await execution.start({ transaction }); | ||||
| 
 | ||||
|     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)) { | ||||
|       await transaction.commit(); | ||||
|     } | ||||
|  | ||||
| @ -23,7 +23,7 @@ MODE_BITMAP_EVENTS.set(MODE_BITMAP.DESTROY, 'afterDestroy'); | ||||
| 
 | ||||
| 
 | ||||
| function getHookId(workflow, type) { | ||||
|   return `${type}#${workflow.get('id')}`; | ||||
|   return `${type}#${workflow.id}`; | ||||
| } | ||||
| 
 | ||||
| // async function, should return promise
 | ||||
| @ -43,12 +43,23 @@ function handler(this: WorkflowModel, data: Model, options) { | ||||
| } | ||||
| 
 | ||||
| export default class CollectionTrigger implements Trigger { | ||||
|   db; | ||||
| 
 | ||||
|   events = new Map(); | ||||
| 
 | ||||
|   constructor({ app }) { | ||||
|     this.db = app.db; | ||||
|   } | ||||
| 
 | ||||
|   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 = database.getCollection(collection); | ||||
|     const Collection = this.db.getCollection(collection); | ||||
|     if (!Collection) { | ||||
|       return; | ||||
|     } | ||||
| @ -60,12 +71,12 @@ export default class CollectionTrigger implements Trigger { | ||||
|         if (!this.events.has(name)) { | ||||
|           const listener = handler.bind(workflow); | ||||
|           this.events.set(name, listener); | ||||
|           database.on(event, listener); | ||||
|           this.db.on(event, listener); | ||||
|         } | ||||
|       } else { | ||||
|         const listener = this.events.get(name); | ||||
|         if (listener) { | ||||
|           database.off(event, listener); | ||||
|           this.db.off(event, listener); | ||||
|           this.events.delete(name); | ||||
|         } | ||||
|       } | ||||
| @ -73,9 +84,8 @@ export default class CollectionTrigger implements Trigger { | ||||
|   } | ||||
| 
 | ||||
|   off(workflow: WorkflowModel) { | ||||
|     const { database } = <typeof WorkflowModel>workflow.constructor; | ||||
|     const { collection, mode } = workflow.config; | ||||
|     const Collection = database.getCollection(collection); | ||||
|     const Collection = this.db.getCollection(collection); | ||||
|     if (!Collection) { | ||||
|       return; | ||||
|     } | ||||
| @ -85,7 +95,7 @@ export default class CollectionTrigger implements Trigger { | ||||
|       if (mode & key) { | ||||
|         const listener = this.events.get(name); | ||||
|         if (listener) { | ||||
|           database.off(event, listener); | ||||
|           this.db.off(event, listener); | ||||
|           this.events.delete(name); | ||||
|         } | ||||
|       } | ||||
|  | ||||
| @ -7,7 +7,8 @@ export interface Trigger { | ||||
|   off(workflow: WorkflowModel): void; | ||||
| } | ||||
| 
 | ||||
| export default function({ triggers }) { | ||||
|   triggers.register('collection', new Collection()); | ||||
|   // triggers.register('schedule', new Schedule());
 | ||||
| export default function(plugin) { | ||||
|   const { triggers } = plugin; | ||||
|   triggers.register('collection', new Collection(plugin)); | ||||
|   // triggers.register('schedule', new Schedule(plugin));
 | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user